Compare commits

...

114 Commits
1.8 ... master

Author SHA1 Message Date
asamihassan 44bab85ba7 person deletion method overload 2022-10-04 19:21:57 +05:00
PCoder 3b30b9666a Update Changlog 2022-09-29 08:58:00 +05:30
PCoder 30f0743c41 #11013: filter persons only with profile_on_web true for public search 2022-09-29 07:40:52 +05:30
PCoder db54e3c3d7 Merge remote-tracking branch 'ungleich-public/master' 2022-09-26 10:48:17 +05:30
PCoder d7199827da Fix infinite redirections in production 2022-09-25 21:21:42 +05:30
app 0574694d38 Revert back 2022-09-25 14:20:51 +00:00
app f88a037edc First working version 2022-09-25 10:19:08 +00:00
app bfe6fe610a Test: disable contents of init.sh 2022-09-24 13:45:40 +00:00
app 19b115434f ++init.sh 2022-09-24 11:51:49 +00:00
PCoder 674ab5d288 Copy init.sh to appropriate path 2022-09-24 16:45:41 +05:30
app 2c870df36c Add init.sh 2022-09-23 03:37:54 +00:00
PCoder 929d279b24 Use storage under /data 2022-09-23 08:18:38 +05:30
app 127a9ab8ec Merge branch 'master' of code.ungleich.ch:ungleich-public/gmba_django 2022-09-23 01:32:03 +00:00
app b7dfb676ec Fix collectstatic 2022-09-23 01:29:27 +00:00
app 079762250b nginx.conf: add missing terminating semicolon 2022-09-22 03:24:21 +00:00
app c7b525875d entrypoint.sh: Avoid using deep link 2022-09-22 03:23:40 +00:00
app 4734789a25 gunicorn: Listen on both ipv6 and ipv4 interfaces 2022-09-22 03:10:45 +00:00
app 3a5cbc6325 Use POSTGRES_HOST and POSTGRES_PORT instead of SQL_* 2022-09-22 03:06:24 +00:00
app a80158da66 Merge branch '10884-dockerify' of code.ungleich.ch:ungleich-public/gmba_django into 10884-dockerify 2022-09-20 04:21:57 +00:00
app 5326ea7ab0 Use psql for dev as well 2022-09-20 04:21:04 +00:00
app 854ce75993 Fix location of manage.py 2022-09-20 04:20:44 +00:00
app 02aaccffed Attempt collectstatic in Dockerfile itselfw 2022-09-20 04:02:47 +00:00
app 5e50d3320e Use the same env file for db and web (.env.prod) 2022-09-20 03:50:41 +00:00
app 0140a65602 Align constants 2022-09-20 03:50:02 +00:00
app 8f2f8b86e2 Use POSTGRES_* constants for uniformity 2022-09-20 03:48:07 +00:00
app e798679c6c Change default db to psql 2022-09-20 03:42:17 +00:00
pcoder116 f85846cd48 Merge pull request '10884-dockerify' (#6) from 10884-dockerify into master
Reviewed-on: #6
2022-09-19 08:27:31 +00:00
PCoder 0123fd2eef Add media files config 2022-09-19 13:35:02 +05:30
PCoder 3eb5ba12d9 Add missing configs for nginx 2022-09-19 13:30:56 +05:30
PCoder bc4061f12a Prepare changelog for 2.0 2022-09-19 12:36:21 +05:30
PCoder 4cc03b6372 Remove unwanted files 2022-09-19 12:22:52 +05:30
PCoder 00c03e7bec Merge remote-tracking branch 'ungleich-public/master' into 10884-dockerify 2022-09-19 10:24:47 +05:30
PCoder 600ae8e5de Fix static files path in nginx.conf 2022-09-19 09:57:57 +05:30
PCoder 13b7918de1 Fix staticfiles path as per code 2022-09-19 09:54:17 +05:30
PCoder a91d2b16b6 Fix static files path and create the directory 2022-09-19 09:43:27 +05:30
app 5b64c4ee15 Use correct container name 2022-09-19 03:57:24 +00:00
app 5446daa87f Use hardcoded instance name for now 2022-09-19 03:35:14 +00:00
asamihassan 48a2585829 person save method overload 2022-09-08 22:44:24 +05:00
asamihassan 2c4fb66176 resource and relevant objs del 2022-09-07 23:48:58 +05:00
app f960c4e779 Add docker-compose.prod.yaml and nginx confs 2022-08-25 08:27:48 +00:00
app 3b9498d13d WIP: fixing docker compose scritps 2022-08-25 08:26:59 +00:00
PCoder 7fd30a5dcd Add production ready Dockerfle and entrypoint files 2022-08-25 11:03:25 +05:30
PCoder c5bfc46e33 Add first version of docker files 2022-08-25 10:26:17 +05:30
asamihassan b7f8e237fa missing search field organisation_english at organizationadmin 2022-05-18 22:12:18 +05:00
asamihassan c84ae636c5 added organisation and acronyms in admin query field 2022-04-12 13:31:14 +05:00
asamihassan 8e409d1a38 space changed too < in __str__ person 2022-04-12 12:47:17 +05:00
asamihassan 808f1d94bb alphabatecial order for query in person admin addition for country and dept 2022-04-12 12:01:31 +05:00
asamihassan 9dc9daa1e0 form to override autocomplete organization changed 2022-03-28 10:46:30 +05:00
asamihassan e8f8ee8ad3 form to override autocomplete organization field for Person class in admin 2022-03-27 23:32:26 +05:00
asamihassan d436650d2c [Persons] Offer caculated autocomplete identifiers 10146 2022-03-27 17:44:32 +05:00
asamihassan e9ec1909b4 download_csv name changed to export (.csv) 2022-03-25 23:35:38 +05:00
asamihassan 0136386ad0 Enable CSV export for the 4 main tables Organisations, Persons, Resources, Mountain ranges 2022-03-25 23:08:02 +05:00
asamihassan cc66cfd4d8 newform submission to client at https://formspree.io/f/xvolqjpe 2022-03-22 23:16:20 +05:00
asamihassan dffd00d8cb form submission to client at https://formspree.io/f/gmba@ips.unibe.ch 2022-03-22 23:05:59 +05:00
asamihassan 7efa5b3741 formspree emails sent to test.gamba.ungleich@gmail.com and form hides 2022-03-17 16:27:42 +05:00
PCoder f2d27bd791 Merge remote-tracking branch 'ungleich-public/master' 2022-03-17 14:04:53 +05:30
PCoder 202b6c0092 Some pending fixes 2022-03-17 14:03:35 +05:30
pcoder116 907ae0c256 Merge pull request 'fix_refresh_data' (#5) from fix_refresh_data into master
Reviewed-on: #5
2022-03-11 11:25:35 +00:00
PCoder 2c83c3e322 Add save method to index 2022-03-11 16:53:15 +05:30
PCoder f272481bf6 Fix finding range from name 2022-03-05 02:09:38 +05:30
PCoder 5b7e4eed3e Fix possible none 2022-03-05 01:32:47 +05:30
PCoder da8fba3497 Fix taxon 2022-03-05 01:28:29 +05:30
PCoder 2dda215ffe Append range name only if not none 2022-03-05 01:23:08 +05:30
PCoder 401b554a1c More debug + create person and update fields if it does not exist in DB 2022-03-05 01:05:23 +05:30
PCoder 27ecafa887 Debug 2022-03-05 01:01:28 +05:30
PCoder a0c3dd57dd Format + improve indexer 2022-03-05 00:44:07 +05:30
PCoder 41a2129e9a Improve refresh_data 2022-03-05 00:43:44 +05:30
PCoder edb860fa16 Update Changelog for 1.12 2022-01-19 12:34:28 +05:30
PCoder e95c87e99c Organization: revert back organization url 2022-01-19 12:28:22 +05:30
PCoder 6715924065 Add migrations 2022-01-17 23:56:48 +05:30
PCoder 0e5a7fb2c8 Merge remote-tracking branch 'ungleich-public/master' 2022-01-17 23:56:17 +05:30
PCoder 461ceb9573 Organization: Reorganize fields 2022-01-17 23:54:29 +05:30
pcoder116 c483ed000a Merge pull request '10112/mountain-range-form-change' (#4) from 10112/mountain-range-form-change into master
Reviewed-on: #4
2022-01-17 18:21:11 +00:00
pcoder116 14cad5b554 Merge branch 'master' into 10112/mountain-range-form-change 2022-01-17 18:20:34 +00:00
PCoder 35094de8a8 PersonAdmin: Remove Mr. and Ms. options for mr_mrs choices 2022-01-17 23:14:48 +05:30
PCoder 9cba842a18 PersonAdmin: Move profile_on_web and newsletter to the top 2022-01-17 23:14:09 +05:30
PCoder 3a29b96513 PersonAdmin: Show organization_url 2022-01-17 23:13:33 +05:30
PCoder 1b9bd6df48 Resource: Fix Atlas showing up as default type for empty one 2022-01-17 20:58:56 +05:30
PCoder caef9906bd Organisation list view update
Show org_num instead of the name (which can be empty)
2022-01-17 20:13:56 +05:30
PCoder 068e38fb91 Rearrange fields 2022-01-13 10:54:03 +05:30
PCoder 7c7ae45ff0 Comment out inlines for MountainRange 2022-01-13 10:45:47 +05:30
PCoder 5974c7530a Move countries after mother range 2022-01-13 10:43:02 +05:30
PCoder 0a3b185c52 Add migration 2022-01-13 10:36:11 +05:30
PCoder d012a2e384 Make range_alternate_id charfield and position it at the bottom 2022-01-13 10:35:46 +05:30
PCoder 5de6645d4f Do not show checked 2022-01-13 10:24:07 +05:30
PCoder 90b4f3e53e Make wiki_data_url urlfield + make it closer to wiki_data_id 2022-01-13 10:14:43 +05:30
PCoder f02ea9e2ea Add migration 2022-01-13 10:07:26 +05:30
PCoder 1c78f6d8e3 Make GMBA narrow boolean field 2022-01-13 10:07:06 +05:30
PCoder 9d022c6d3e Make GMBA Standard close to select_300 2022-01-13 10:06:33 +05:30
PCoder 55ec614dd6 Load boolean data from select_300 field while import 2022-01-13 09:46:04 +05:30
PCoder 4c328052da Make select_300 boolean field 2022-01-13 09:45:40 +05:30
PCoder a81740f453 Make select_300 boolean field 2022-01-13 09:38:36 +05:30
PCoder aad89cdcbe Update Changelog 2022-01-05 22:49:17 +05:30
PCoder e893460993 Upgrade Django to 4.0.1 2022-01-05 22:41:15 +05:30
PCoder cbba1b99e4 Update Changelog and upgrade Django version to 3.2.11 2022-01-05 22:26:10 +05:30
PCoder a410c5c320 Remove unwanted spaces 2022-01-05 22:18:59 +05:30
PCoder fc78d8d962 Make gmba_v2_id not editable 2022-01-05 22:18:43 +05:30
PCoder fdb9dc15de Make Person model ordering by full_name by default 2022-01-05 22:18:21 +05:30
PCoder fa6d20901a Update Changelog 2022-01-05 21:37:54 +05:30
pcoder116 b3d43f802d Merge pull request '10105/improve-person-detail-load-time' (#3) from 10105/improve-person-detail-load-time into master
Reviewed-on: #3
2022-01-05 15:53:12 +00:00
PCoder 5d5731a090 Add autocomplete_fields mother_range to RangeAdmin 2022-01-05 21:21:35 +05:30
PCoder ca20e1490e Optimize MountainRange admin page load time 2022-01-05 21:02:12 +05:30
PCoder 77f8d6da89 Optimize Resource detail admin page 2022-01-05 20:51:40 +05:30
PCoder 32b7d4e395 Reduce number of requests in the persons detail view + Optimize 2022-01-05 19:43:14 +05:30
PCoder f8b0dbcf4a Update Changelog 2022-01-04 23:18:37 +05:30
pcoder116 5d71cd8182 Merge pull request '10106/update-list-view' (#1) from 10106/update-list-view into master
Reviewed-on: #1
2022-01-04 17:46:39 +00:00
PCoder 9130fab8a5 Merge branch 'master' into 10106/update-list-view 2022-01-04 23:15:24 +05:30
PCoder f2bc11d469 Update Changelog 2022-01-04 23:12:02 +05:30
pcoder116 4c759a3609 Merge pull request '10077/efficient-input-lookup' (#2) from 10077/efficient-input-lookup into master
Reviewed-on: #2
2022-01-04 17:36:11 +00:00
PCoder 7162dc6c8c Revert back changes from the other pull request 2022-01-04 23:02:09 +05:30
PCoder 98abe82b1d Use autocomplete fields for looking up organization 2022-01-04 22:57:56 +05:30
PCoder 99f14d0ce4 Change issue number 2022-01-04 22:31:14 +05:30
PCoder d70284d1fc Update Changelog 2022-01-04 22:30:35 +05:30
PCoder 1c2641af0d Update the list view
Organisation : add country to the list at the end
Mountain Ranges: add country at the end. sort the range names in alphabetical order.
Persons: should have organisation name in the list view
Resources: Alphabetically sort the titles
2022-01-04 22:27:04 +05:30
26 changed files with 867 additions and 151 deletions

View File

@ -1,5 +1,74 @@
# CHANGELOG.md
## 2.1 (2022-09-29)
- issue#11013: non-public entries appearing as public
## 2.0 (2022-09-19) Dockerify https://redmine.ungleich.ch/issues/10884
Steps:
- Create .env.prod and .env.prod.db files
#### .env.prod
```
DEBUG=0
SECRET_KEY=secret_key_here
DJANGO_SETTINGS_MODULE=gmba_django.settings.production
ALLOWED_HOSTS=localhost,127.0.0.1,[::1]
POSTGRES_USER=user
POSTGRES_PASSWORD=password
POSTGRES_DB=app
POSTGRES_HOST=db
POSTGRES_PORT=5432
```
Building containers
- docker-compose -f docker-compose.prod.yml down -v --remove-orphans
- docker-compose -f docker-compose.prod.yml up -d --build
Copy db and adust
- docker cp gd.sql gmba_django_db_1:/gd.sql
- docker-compose exec db psql --username=psql_username_name --dbname=psql_db_name < /gd.sql
Migrate / check
- docker-compose exec web python manage.py migrate --noinput
Static resources
- docker-compose -f docker-compose.prod.yml exec web python manage.py collectstatic --no-input --clear
## 1.12 (2022-01-19)
Bugfixes:
- issue#10112: Mountain Range admin form reorganization
- issue#10149: Fix for organization name empty case
- issue#10147: Fix atlas showing up as default type for many Resources
- issue#10142: Person admin form enhancements
## 1.11 (2022-01-05)
Bugfixes:
- issue#10111
- 'Gmba v2 id:' is editable at the moment, it shouldn't be editable
Upgrades:
- issue#10113
- Django from 3.2.5 to 3.2.11 and then to 4.0.1
## 1.10 (2022-01-05)
Enhancements:
- issue#10105
- Improve admin page load time for Person, Resource and MountainRange
## 1.9 (2022-01-04)
Bugfixes:
- issue#10106
- Organisation : add country to the list at the end
- Mountain Ranges: add country at the end. sort the range names in alphabetical order.
- Persons: should have organisation name in the list view
- Resources: Alphabetically sort the titles
- issue#10077: efficient input lookup for organization column in Person
## 1.8 (2022-01-04)
Bugfixes:
@ -78,4 +147,4 @@ Bugfixes:
Features:
- First release includes functioning django admin interfaces for
`Person` and `Range` models
`Person` and `Range` models

85
Dockerfile.prod Normal file
View File

@ -0,0 +1,85 @@
###########
# BUILDER #
###########
# pull official base image
FROM python:3.9.6-alpine as builder
# set work directory
WORKDIR /usr/src/gmba_django
# set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
# install psycopg2 dependencies
RUN apk update \
&& apk add postgresql-dev gcc python3-dev musl-dev
# lint
RUN pip install --upgrade pip
RUN pip install flake8==3.9.2
COPY . .
#RUN flake8 --ignore=E501,F401 .
# install dependencies
COPY ./requirements.txt .
RUN pip wheel --no-cache-dir --no-deps --wheel-dir /usr/src/gmba_django/wheels -r requirements.txt
#########
# FINAL #
#########
# pull official base image
FROM python:3.9.6-alpine
# create directory for the app user
RUN mkdir -p /home/app
# create the app user
RUN addgroup -S app && adduser -S app -G app
# create the appropriate directories
ENV HOME=/home/app
ENV APP_HOME=/home/app/gmba_django
RUN mkdir $APP_HOME
RUN mkdir $APP_HOME/static
RUN mkdir $APP_HOME/media
#ADD gmba_django /data/app
#WORKDIR /data/app/gmba_django
# install dependencies
RUN apk update && apk add libpq
COPY --from=builder /usr/src/gmba_django/wheels /wheels
COPY --from=builder /usr/src/gmba_django/requirements.txt .
RUN pip install --no-cache /wheels/*
# copy entrypoint.prod.sh
COPY ./entrypoint.prod.sh /entrypoint.prod.sh
COPY ./init.sh /init.sh
RUN sed -i 's/\r$//g' /entrypoint.prod.sh
RUN chmod +x /entrypoint.prod.sh
# copy project
#COPY . $APP_HOME
ADD . /home/app/gmba_django
WORKDIR /home/app/gmba_django
# chown all the files to the app user
RUN chown -R app:app $APP_HOME
# change to the app user
USER app
#RUN python manage.py collectstatic --noinput
# run entrypoint.prod.sh
ENTRYPOINT ["/entrypoint.prod.sh"]
EXPOSE 8000
CMD ["gunicorn", "--bind", "[::]:8000", "--chdir", "/home/app/gmba_django", "--workers", "3", "gmba_django.wsgi:application"]

View File

@ -1,15 +1,65 @@
from re import A
from unicodedata import name
from django.contrib import admin
from django.utils.html import format_html
from .models import *
from django.forms import TextInput
from django.conf import settings
from django.http import HttpResponse
import csv
from django import forms
from django.contrib.admin.widgets import AutocompleteSelect
from django.contrib import messages # import messages
class autocomplete_fields_form(forms.ModelForm):
"""This form overrides autocomplete
organization field for Person class
"""
def __init__(self, *args, **kwargs):
super(autocomplete_fields_form, self).__init__(*args, **kwargs)
# self.fields['organization'].label = 'My new label'
class Meta:
model = Person
fields = '__all__'
widgets = {
'organization': forms.Select(attrs={'style': 'width:750px'})
}
def download_csv(modeladmin, request, queryset):
name = queryset[0].__class__.__name__
response = HttpResponse()
response['Content-Disposition'] = "attachment; filename="+name+"_table.csv"
first_row = []
for i in queryset[0]._meta.__dict__.get("fields"):
temp = str(i).split('.')
first_row.append(temp[-1])
writer = csv.writer(response)
writer.writerow(first_row)
for dic in queryset.values():
temp_list = (list(dic.values()))
writer.writerow(temp_list)
return response
download_csv.short_description = 'export (.csv)'
class PeopleResourceInline(admin.TabularInline):
autocomplete_fields = ['resource']
model = PeopleResource
extra = 0
class PeopleRangeInline(admin.TabularInline):
autocomplete_fields = ['range']
model = PeopleRange
extra = 0
class PersonAdmin(admin.ModelAdmin):
@ -18,12 +68,13 @@ class PersonAdmin(admin.ModelAdmin):
PeopleRangeInline
]
readonly_fields = ['id']
search_fields = ['title', 'first_name', 'last_name', 'organisation', 'position', 'country__short_name', 'contact_email']
search_fields = ['title', 'first_name', 'last_name', 'organisation',
'position', 'country__short_name', 'contact_email']
fieldsets = (
(None, {
'fields': (
('id'),
('mr_mrs', 'title','full_name', 'position'),
('id', 'profile_on_web', 'news_letter'),
('mr_mrs', 'title', 'full_name', 'position'),
('first_name', 'last_name', 'search_name', 'status'),
('contact_email', 'email_2', 'skype', 'professional_phone'),
'organization',
@ -35,7 +86,7 @@ class PersonAdmin(admin.ModelAdmin):
('Research Scale', {
'classes': ('collapse',),
'fields': (('field_site', 'transect', 'mountain_top', 'mountain_range', 'landscape', 'regional', 'national',),
'_global'),
'_global'),
}),
('Methods and tools', {
'classes': ('collapse',),
@ -50,28 +101,122 @@ class PersonAdmin(admin.ModelAdmin):
}),
('Others', {
'classes': ('collapse',),
'fields': ('orcid', 'web_of_science', 'twitter', 'instagram', 'updated',
('news_letter', 'profile_on_web'),
'entry_date',
'country',
'gmba_function'
),
'fields': (
'orcid', 'web_of_science', 'twitter', 'instagram', 'updated',
'entry_date',
'country',
'gmba_function'
),
}),
)
list_display = ['id', 'full_name' ]
# list_display_links = ['id']
list_display = ['id', 'full_name', 'organization']
#autocomplete_fields = ['organization']
form = autocomplete_fields_form # adjust width of autocomplete_fields organization
list_per_page = settings.ADMIN_LIST_PER_PAGE
ordering = ['full_name']
actions = [download_csv]
def get_field_queryset(self, db, db_field, request):
queryset = super().get_field_queryset(db, db_field, request)
if db_field.name == 'organization':
queryset = queryset.order_by(
'country', 'organisation_english', 'organisation_2', 'organisation_3', 'acronym')
return queryset
def get_actions(self, request):
actions = super().get_actions(request)
if 'delete_selected' in actions:
del actions['delete_selected']
return actions
def delete_model(self, request, obj):
self.delete_person(request, obj)
return super(PersonAdmin, self).delete_model(request, obj)
def delete_person(self, request, obj):
taxa_people = TaxaPeople.objects.filter(person=obj.id)
for i in taxa_people:
i.delete()
ranges_people = RangesPeople.objects.filter(person=obj.id)
for i in ranges_people:
i.delete()
resources_people = ResourcesPeople.objects.filter(person=obj.id)
for i in resources_people:
i.delete()
scales_people = ScalesPeople.objects.filter(person=obj.id)
for i in scales_people:
i.delete()
people_function = PeopleFunction.objects.filter(person=obj.id)
for i in people_function:
i.delete()
people_range = PeopleRange.objects.filter(person=obj.id)
for i in people_range:
i.delete()
people_resources = PeopleResource.objects.filter(person=obj.id)
for i in people_resources:
i.delete()
fields_people = FieldsPeople.objects.filter(person=obj.id)
for i in fields_people:
i.delete()
methods_people = MethodsPeople.objects.filter(person=obj.id)
for i in methods_people:
i.delete()
def delete_persons(self, request, obj):
for o in obj.all():
taxa_people = TaxaPeople.objects.filter(person=o.id)
for i in taxa_people:
i.delete()
ranges_people = RangesPeople.objects.filter(person=o.id)
for i in ranges_people:
i.delete()
resources_people = ResourcesPeople.objects.filter(person=o.id)
for i in resources_people:
i.delete()
scales_people = ScalesPeople.objects.filter(person=o.id)
for i in scales_people:
i.delete()
people_function = PeopleFunction.objects.filter(person=o.id)
for i in people_function:
i.delete()
people_range = PeopleRange.objects.filter(person=o.id)
for i in people_range:
i.delete()
people_resources = PeopleResource.objects.filter(person=o.id)
for i in people_resources:
i.delete()
fields_people = FieldsPeople.objects.filter(person=o.id)
for i in fields_people:
i.delete()
methods_people = MethodsPeople.objects.filter(person=o.id)
for i in methods_people:
i.delete()
o.delete()
messages.success(request, "Successfully deleted")
delete_persons.short_description = 'Delete Person & Related Fields'
actions = [download_csv, delete_persons]
class ResourceKeywordInline(admin.TabularInline):
autocomplete_fields = ['keyword']
model = ResourceKeyword
extra = 0
class ResourceRangeInline(admin.TabularInline):
autocomplete_fields = ['range_name']
model = ResourceRange
extra = 0
class ResourcePeopleInline(admin.TabularInline):
autocomplete_fields = ['person']
model = PeopleResource
extra = 0
formfield_overrides = {
models.CharField: {'widget': TextInput(attrs={'size': '20'})}
}
@ -86,6 +231,7 @@ class ResourceAdmin(admin.ModelAdmin):
search_fields = ['title', 'url', 'citation', 'abstract']
readonly_fields = ['id']
list_display = ['title', 'citation', 'type']
ordering = ['title']
fieldsets = (
(None, {
'fields': (
@ -114,34 +260,85 @@ class ResourceAdmin(admin.ModelAdmin):
'PEGASuS_Check_map_with_author',),)
}),
)
list_per_page = settings.ADMIN_LIST_PER_PAGE
def get_actions(self, request):
actions = super().get_actions(request)
if 'delete_selected' in actions:
del actions['delete_selected']
return actions
def delete_model(self, request, obj):
self.delete_resource(request, obj)
return super(ResourceAdmin, self).delete_model(request, obj)
def delete_resource(self, request, obj):
resource_keyword = ResourceKeyword.objects.filter(resource=obj.id)
for i in resource_keyword:
i.delete()
resource_range = ResourceRange.objects.filter(resource_title=obj.id)
for i in resource_range:
i.delete()
resource_people = ResourcesPeople.objects.filter(resource=obj.id)
for i in resource_people:
i.delete()
resource_people_resource = PeopleResource.objects.filter(
resource=obj.id)
for i in resource_people_resource:
i.delete()
def delete_resources(self, request, obj):
for o in obj.all():
resource_keyword = ResourceKeyword.objects.filter(resource=o.id)
for i in resource_keyword:
i.delete()
resource_range = ResourceRange.objects.filter(resource_title=o.id)
for i in resource_range:
i.delete()
resource_people = ResourcesPeople.objects.filter(resource=o.id)
for i in resource_people:
i.delete()
resource_people_resource = PeopleResource.objects.filter(
resource=o.id)
for i in resource_people_resource:
i.delete()
o.delete()
messages.success(request, "Successfully deleted")
delete_resources.short_description = 'Delete Resource & Related Fields'
actions = [download_csv, delete_resources]
class RangeNameTranslationInline(admin.TabularInline):
autocomplete_fields = ['language_translation']
model = RangeNameTranslation
extra = 0
class RangeCountryInline(admin.TabularInline):
autocomplete_fields = ['country']
model = RangeCountry
extra = 0
class RangeAdmin(admin.ModelAdmin):
inlines = [
RangeNameTranslationInline,
RangeCountryInline
]
readonly_fields = ('id',)
autocomplete_fields = ['mother_range']
# inlines = [
# RangeNameTranslationInline,
# RangeCountryInline
# ]
readonly_fields = ('id', 'gmba_v2_id')
search_fields = ['name', 'range_name', 'range_name_ascii',
'level', 'level', 'level_1', 'level_2', 'level_3', 'peak_name', 'comments', 'source',
'name_fr', 'name_de', 'name_es', 'name_pt', 'name_cn', 'name_ru', 'name_tr']
fieldsets = (
(None, {
'fields': (
('gmba_v2_id', 'range_name', 'range_name_language', 'map_unit'),
('range_name_map', 'select_300', 'checked'),
('range_name_ascii', 'GMBA_v1_id'),
('latitude', 'longitude'),
('mother_range', 'wiki_data_id', 'area'),
('feature', 'range_alternate_id', 'gmba_narrow'),
('gmba_v2_id', 'range_name', 'range_name_language'),
('map_unit', 'feature', 'gmba_narrow', 'select_300'),
('range_name_map', 'range_name_ascii', 'GMBA_v1_id'),
('latitude', 'longitude', 'area'),
('mother_range', 'countries', 'wiki_data_id', 'wiki_data_url'),
'source',
'id',
)
@ -153,16 +350,19 @@ class RangeAdmin(admin.ModelAdmin):
('name_ru', 'name_tr', 'name_cn')
)
}),
('Range Countries', {
'classes': ('collapse',),
'fields': ('countries',),
}),
('Comments', {
'classes': ('collapse',),
'fields': ('comments',),
}),
('Others', {
'fields': ('range_alternate_id', )
})
)
list_display = ['range_name', 'countries', 'mother_range']
list_display = ['range_name', 'mother_range', 'countries']
ordering = ['range_name']
list_per_page = settings.ADMIN_LIST_PER_PAGE
actions = [download_csv]
class PeopleOrganizationInline(admin.TabularInline):
@ -176,14 +376,17 @@ class OrganizationAdmin(admin.ModelAdmin):
PeopleOrganizationInline,
]
readonly_fields = ('org_num1',)
search_fields = ['organisation_search', 'org_alpha_search', 'organisation_2', 'organisation_3', 'subject']
list_display = ['organisation_english', 'organisation_2']
search_fields = ['organisation_search', 'org_alpha_search',
'organisation_2', 'organisation_3', 'subject', 'organisation_english']
list_display = ['org_num1', 'organisation_english',
'organisation_2', 'country']
fieldsets = (
(None, {
'fields': (
'org_num1',
('acronym', 'category', 'subject'),
'organisation_english',
'country',
('organisation_english', 'tel', 'email', 'url',),
('organisation_2', 'organisation_3'),
'organisation_original',
)
@ -192,19 +395,18 @@ class OrganizationAdmin(admin.ModelAdmin):
'classes': ('collapse',),
'fields': (
('street', 'postcode', 'city'),
('po_box', 'country', 'lat_long'),
('po_box', 'lat_long'),
)
}),
('Other details', {
'classes': ('collapse',),
'fields': (('tel', 'email'),
'url',
'tags',
),
'fields': (
'tags',
),
})
)
ordering = [ 'organisation_english' ]
ordering = ['organisation_english']
actions = [download_csv]
def org_url(self, instance):
return format_html('<a href="{0}" target="_blank">{1}</a>',
@ -297,7 +499,8 @@ class SpeciesAdmin(admin.ModelAdmin):
class TaxonRangeAdmin(admin.ModelAdmin):
model = TaxonRange
search_fields = ['range__range_name', 'taxon', 'subrange_or_region', 'distribution', 'source', 'remarks']
search_fields = ['range__range_name', 'taxon',
'subrange_or_region', 'distribution', 'source', 'remarks']
list_display = ['range_name', 'taxon']
def range_name(self, obj):
@ -357,20 +560,27 @@ class RangeCountryAdmin(admin.ModelAdmin):
return str(obj.country.short_name) if obj.country else 'None'
class KeywordAdmin(admin.ModelAdmin):
search_fields = ['keyword']
# Register your models here.
admin.site.register(Person, PersonAdmin)
admin.site.register(Resource, ResourceAdmin)
admin.site.register(MountainRange, RangeAdmin)
admin.site.register(Keyword, KeywordAdmin)
# admin.site.register(Method)
# admin.site.register(Scale)
# admin.site.register(Taxon)
# admin.site.register(Field, FieldAdmin)
admin.site.disable_action('delete_selected')
# LU models
# admin.site.register(Country, CountriesAdmin)
admin.site.register(Country, CountriesAdmin)
# admin.site.register(GMBA_SpeciesGroup, GMBA_SpeciesGroupAdmin)
# admin.site.register(Language, LanguageAdmin)
admin.site.register(Language, LanguageAdmin)
# admin.site.register(PeopleStatus, PeopleStatusAdmin)
# admin.site.register(RangeType, RangeTypeAdmin)
# admin.site.register(RedListCategory, RedListCategoryAdmin)

View File

@ -39,7 +39,7 @@ def add_linked(person, obj, data):
tgt.name = n
tgt.save()
field.append(tgt)
return field
return field
# Fetch an object by source_id (numeric identifier used in source DB)
@ -71,7 +71,8 @@ def reindex_data():
# Data update routine
def refresh_data(filename, fmt=None):
def refresh_data(filename, fmt=None, update_existing=False):
print("refresh_data")
count = 0
rowcount = 0
if not isfile(filename):
@ -101,42 +102,72 @@ def refresh_data(filename, fmt=None):
return None
if fmt['dataformat'] is DataFormat.PERSON_DETAIL:
print(row)
person, source_id = get_by_id(row['ID'], Person)
if not person:
person = Person.objects.filter(first_name=row['First name'], last_name=row['Last name']).first()
if person:
print("Fetched from DB")
else:
print("Does not exist in DB")
if not person:
person = Person(first_name=row['First name'], last_name=row['Last name'], source_id=row['ID'])
person.source_id = source_id
person.title = row['Title']
print(row)
person.organisation = row['Organisation English']
print("Country = %s" % row['country'] if 'country' in row else '')
if 'country' not in row or row['country'] is None or row['country'].strip() == '':
row['country'] = 0
c = Country.objects.get(id=row['country'])
person.country = c
person.position = row['Position']
person.biography = row['Biography']
person.contact_email = row['e-mail 1']
person.personal_url = fix_url(row['URL'])
person.save()
print("Created")
# Update data fields
person.source_id = source_id
person.title = row['Title']
person.organisation = row['Organisation English']
print("Country = %s" % row['country'])
if row['country'] is None or row['country'].strip() == '':
row['country'] = 0
c = Country.objects.get(id=row['country'])
person.country = c
person.position = row['Position']
person.biography = row['Biography']
person.contact_email = row['e-mail 1']
person.personal_url = fix_url(row['URL'])
if update_existing:
person.source_id = source_id
person.title = row['Title']
print(row)
person.organisation = row['Organisation English']
print("Country = %s" % row['country'] if 'country' in row else '')
if 'country' not in row or row['country'] is None or row['country'].strip() == '':
row['country'] = 0
c = Country.objects.get(id=row['country'])
person.country = c
person.position = row['Position']
person.biography = row['Biography']
person.contact_email = row['e-mail 1']
person.personal_url = fix_url(row['URL'])
person.save()
with transaction.atomic():
research_methods = add_linked(person, Method, row['Methods'])
methods_people = [MethodsPeople.objects.get_or_create(method_id=m.id, person_id=person.id) for m in research_methods]
methods_people = [MethodsPeople.objects.get_or_create(method_id=m.id, person_id=person.id)[0] for m in research_methods]
person.methodspeople_set.set(methods_people)
research_scales = add_linked(person, Scale, row['Scale'])
scales_people = [ScalesPeople.objects.get_or_create(scale_id=s.id, person_id=person.id) for s in research_scales]
scales_people = [ScalesPeople.objects.get_or_create(scale_id=s.id, person_id=person.id)[0] for s in research_scales]
person.scalespeople_set.set(scales_people)
research_taxa = add_linked(person, Taxon, row['Taxa'])
taxa_people = [TaxaPeople.objects.get_or_create(taxon_id=t.id, person_id=person.id) for t in research_taxa]
taxa_people = [TaxaPeople.objects.get_or_create(taxon_id=t.id, person_id=person.id)[0] for t in research_taxa]
person.taxapeople_set.set(taxa_people)
research_fields = add_linked(person, Field, row['Field of expertise'])
fields_people = [FieldsPeople.objects.get_or_create(field_id=f.id, person_id=person.id) for f in research_fields]
fields_people = [FieldsPeople.objects.get_or_create(field_id=f.id, person_id=person.id)[0] for f in research_fields]
person.fieldspeople_set.set(fields_people)
# research_ranges = add_linked(person, MountainRange, row['MountainRange'])
# ranges_people = [RangesPeople.objects.get_or_create(range_id=r.id, person_id=person.id)[0] for r in research_ranges]
# person.rangespeople_set.set(ranges_people)
person.index()
person.save()
count = count + 1
elif fmt['dataformat'] is DataFormat.RESOURCE_DETAIL:
res, source_id = get_by_id(row['ID'], Resource)
if not res: res = Resource(source_id=source_id)
if not res:
res = Resource(source_id=source_id)
res.title = row['Title']
res.citation = row['Citation']
res.url = fix_url(row['URL'].strip('#')) # remove weird #formatting#
@ -155,9 +186,11 @@ def refresh_data(filename, fmt=None):
elif fmt['dataformat'] is DataFormat.PERSON_RESOURCE:
rzs, source_id = get_by_id(row['Resource'], Resource, first=False)
if not rzs or not rzs.first(): continue
if not rzs or not rzs.first():
continue
ppl, source_id = get_by_id(row['Person'], Person, first=False)
if not ppl or not ppl.first(): continue
if not ppl or not ppl.first():
continue
for person in ppl:
person.resources = []
for r in rzs:
@ -167,15 +200,30 @@ def refresh_data(filename, fmt=None):
elif fmt['dataformat'] is DataFormat.PERSON_RANGE:
rzs, source_id = get_by_id(row['MountainRange'], MountainRange, first=False)
print(" range=%s, source_id=%s" % (rzs, source_id))
if not rzs or not rzs.first():
print(" --- No rzs, continue")
continue
ppl, source_id = get_by_id(row['Person'], Person, first=False)
if not ppl or not ppl.first(): continue
for person in ppl:
person.ranges = []
for r in rzs:
person.ranges.append(r)
print(" +++ ppl=%s, source_id=%s" % (ppl, source_id))
if not ppl or not ppl.first():
print(" --- No ppl, continue")
continue
with transaction.atomic():
person = ppl.first()
research_ranges = add_linked(person, MountainRange, row['MountainRange'])
ranges_people = [PeopleRange.objects.get_or_create(range_id=r.id, person_id=person.id)[0] for r in research_ranges]
person.peoplerange_set.set(ranges_people)
# for person in ppl:
# research_ranges = add_linked(person, MountainRange, row['MountainRange'])
# ranges_people = [RangesPeople.objects.get_or_create(range_id=r.id, person_id=person.id)[0] for r in research_ranges]
# person.rangespeople_set.set(ranges_people)
# ranges_people = RangesPeople
# for r in rzs:
# ranges_people.append(r)
# person.rangespeople_set.set(ranges_people)
person.save()
#print(" *** Saved %s => %s (%s)" % (person, ranges_people, len(ranges_people)))
count = count + 1
elif fmt['extension'] == 'geojson':

View File

@ -356,7 +356,7 @@ class Command(BaseCommand):
for k, v in self.csv_files_models_dict.items():
if v.strip().lower() == model_name.strip().lower():
csv_file_name = k
if k == '':
if csv_file_name == '':
raise Exception('Could not find a csv file name for model %s' % model_name)
if csv_folder_path.endswith('/'):
file_path = '%s%s' % (csv_folder_path, csv_file_name)
@ -452,6 +452,12 @@ def handle_object_dict(object_dict, model_name, debug=False):
for i in ['checked']:
if i in object_dict:
object_dict[i] = True if object_dict[i].lower().strip() == 'true' else False
for i in ['select_300']:
if i in object_dict:
object_dict[i] = True if object_dict[i].lower().strip() == 'x' else False
for i in ['gmba_narrow']:
if i in object_dict:
object_dict[i] = True if object_dict[i].lower().strip() == 'x' else False
# area field can't be empty
if 'area' in object_dict:
if object_dict['area'] == '':

View File

@ -0,0 +1,18 @@
# Generated by Django 4.0.1 on 2022-01-13 04:08
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('app', '0051_auto_20220104_1608'),
]
operations = [
migrations.AlterField(
model_name='mountainrange',
name='select_300',
field=models.BooleanField(blank=True, max_length=12, null=True),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.0.1 on 2022-01-13 04:15
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('app', '0052_alter_mountainrange_select_300'),
]
operations = [
migrations.AlterField(
model_name='mountainrange',
name='select_300',
field=models.BooleanField(default=False),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.0.1 on 2022-01-13 04:37
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('app', '0053_alter_mountainrange_select_300'),
]
operations = [
migrations.AlterField(
model_name='mountainrange',
name='gmba_narrow',
field=models.BooleanField(default=False, verbose_name='GMBA Standard'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.0.1 on 2022-01-13 04:44
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('app', '0054_alter_mountainrange_gmba_narrow'),
]
operations = [
migrations.AlterField(
model_name='mountainrange',
name='wiki_data_url',
field=models.URLField(blank=True, null=True),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.0.1 on 2022-01-13 05:05
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('app', '0055_alter_mountainrange_wiki_data_url'),
]
operations = [
migrations.AlterField(
model_name='mountainrange',
name='range_alternate_id',
field=models.CharField(blank=True, max_length=128, null=True),
),
]

View File

@ -0,0 +1,23 @@
# Generated by Django 4.0.1 on 2022-01-17 18:26
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('app', '0056_alter_mountainrange_range_alternate_id'),
]
operations = [
migrations.AlterField(
model_name='person',
name='mr_mrs',
field=models.TextField(blank=True, choices=[('', ''), ('Ms', 'Ms'), ('Mr', 'Mr')], null=True),
),
migrations.AlterField(
model_name='resource',
name='type',
field=models.TextField(blank=True, choices=[('', ''), ('Atlas', 'Atlas'), ('Book', 'Book'), ('Book chapter', 'Book chapter'), ('Case study', 'Case study'), ('Conservation project', 'Conservation project'), ('Dataset', 'Dataset'), ('Development project', 'Development project'), ('Journal article', 'Journal article'), ('LTER', 'LTER'), ('Map', 'Map'), ('Network', 'Network'), ('PEGASuS', 'PEGASuS'), ('Presentation', 'Presentation'), ('Report', 'Report'), ('Research project', 'Research project'), ('Research Site', 'Research Site'), ('Thesis', 'Thesis'), ('Video', 'Video'), ('Website', 'Website'), ('Working Group', 'Working Group')], null=True),
),
]

View File

@ -31,7 +31,8 @@ class Field(models.Model):
class FieldsPeople(models.Model):
id = models.AutoField(primary_key=True)
person = models.ForeignKey('Person', models.DO_NOTHING, blank=True, null=True)
person = models.ForeignKey(
'Person', models.DO_NOTHING, blank=True, null=True)
field = models.ForeignKey(Field, models.DO_NOTHING, blank=True, null=True)
class Meta:
@ -53,8 +54,10 @@ class Method(models.Model):
class MethodsPeople(models.Model):
id = models.AutoField(primary_key=True)
person = models.ForeignKey('Person', models.DO_NOTHING, blank=True, null=True)
method = models.ForeignKey(Method, models.DO_NOTHING, blank=True, null=True)
person = models.ForeignKey(
'Person', models.DO_NOTHING, blank=True, null=True)
method = models.ForeignKey(
Method, models.DO_NOTHING, blank=True, null=True)
class Meta:
db_table = 'methods_people'
@ -92,10 +95,14 @@ class MountainRange(models.Model):
#range_name_map = models.CharField(blank=True, null=True, unique=True, max_length=128)
range_name = models.CharField(blank=True, null=True, max_length=128)
range_name_ascii = models.CharField(blank=True, null=True, max_length=128)
range_name_language = models.ForeignKey(Language, models.DO_NOTHING, blank=True, null=True, to_field='id')
mother_range = models.ForeignKey("self", models.DO_NOTHING, blank=True, null=True, to_field='id')
feature = models.ForeignKey(RangeType, models.DO_NOTHING, blank=True, null=True, to_field='id')
map_unit = models.TextField(blank=True, null=True, choices=MAP_UNIT_CHOICES)
range_name_language = models.ForeignKey(
Language, models.DO_NOTHING, blank=True, null=True, to_field='id')
mother_range = models.ForeignKey(
"self", models.DO_NOTHING, blank=True, null=True, to_field='id')
feature = models.ForeignKey(
RangeType, models.DO_NOTHING, blank=True, null=True, to_field='id')
map_unit = models.TextField(
blank=True, null=True, choices=MAP_UNIT_CHOICES)
level = models.TextField(blank=True, null=True)
level_text = models.TextField(blank=True, null=True)
level_1 = models.TextField(blank=True, null=True)
@ -113,14 +120,16 @@ class MountainRange(models.Model):
comments = models.TextField(blank=True, null=True)
checked = models.BooleanField(default=False)
source = models.TextField(blank=True, null=True)
range_alternate_id = models.TextField(blank=True, null=True)
range_alternate_id = models.CharField(
blank=True, null=True, max_length=128)
geologic_region = models.TextField(blank=True, null=True)
gmba_v2_id = models.PositiveIntegerField(blank=True, null=True)
gmba_v2_id_str = models.TextField(blank=True, null=True)
wiki_data_id = models.CharField(blank=True, null=True, max_length=25)
wiki_data_url = models.TextField(blank=True, null=True)
select_300 = models.CharField(blank=True, null=True, max_length=12)
gmba_narrow = models.CharField(blank=True, null=True, max_length=12)
wiki_data_url = models.URLField(blank=True, null=True)
select_300 = models.BooleanField(default=False)
gmba_narrow = models.BooleanField(
default=False, verbose_name="GMBA Standard")
name_fr = models.CharField(blank=True, null=True, max_length=128)
name_de = models.CharField(blank=True, null=True, max_length=128)
name_es = models.CharField(blank=True, null=True, max_length=128)
@ -163,7 +172,8 @@ class Resource(models.Model):
("*****", "*****"),
)
TYPE_CHOICES = (
("", "Atlas"),
("", ""),
("Atlas", "Atlas"),
("Book", "Book"),
("Book chapter", "Book chapter"),
("Case study", "Case study"),
@ -200,7 +210,8 @@ class Resource(models.Model):
PEGASuS_Check_map_with_author = models.BooleanField(default=False)
PEGASuS_polygon_ID = models.CharField(max_length=32, blank=True, null=True)
PEGASuS_Polygon_comments = models.TextField(blank=True, null=True)
PEGASuS_Assessment_ID = models.CharField(max_length=32, blank=True, null=True)
PEGASuS_Assessment_ID = models.CharField(
max_length=32, blank=True, null=True)
gloria = models.BooleanField(default=False)
gnomo = models.BooleanField(default=False)
lter = models.BooleanField(default=False)
@ -351,15 +362,20 @@ class GMBA_function(models.Model):
class Organisation(models.Model):
CATEGORY_CHOICES = (
('Independent', 'Independent'),
('Public administration > Research Institution', 'Public administration > Research Institution'),
('Public administration > Research Institution',
'Public administration > Research Institution'),
('Academia > University > Institute', 'Academia > University > Institute'),
('Academia > University', 'Academia > University'),
('Public administration > Other Agency', 'Public administration > Other Agency'),
('Public administration > Other Agency',
'Public administration > Other Agency'),
('Private > NGO (not for profit)', 'Private > NGO (not for profit)'),
('Academia > Academy of Sciences', 'Academia > Academy of Sciences'),
('Academia > Academy of Sciences > Institute', 'Academia > Academy of Sciences > Institute'),
('Public administration > Government', 'Public administration > Government'),
('Intergovernmental Agency > Research Institution', 'Intergovernmental Agency > Research Institution'),
('Academia > Academy of Sciences > Institute',
'Academia > Academy of Sciences > Institute'),
('Public administration > Government',
'Public administration > Government'),
('Intergovernmental Agency > Research Institution',
'Intergovernmental Agency > Research Institution'),
('Intergovernmental Agency', 'Intergovernmental Agency '),
('Private > Research Institution', 'Private > Research Institution'),
('Collection > Museum', 'Collection > Museum'),
@ -383,7 +399,8 @@ class Organisation(models.Model):
('Culture / arts', 'Culture / arts'),
('Geography', 'Geography'),
('Zoology', 'Zoology'),
('Development / poverty / human rights', 'Development / poverty / human rights'),
('Development / poverty / human rights',
'Development / poverty / human rights'),
('Social Sciences', 'Social Sciences'),
('Earth Sciences', 'Earth Sciences'),
('Health', 'Health'),
@ -398,9 +415,12 @@ class Organisation(models.Model):
org_num1 = models.AutoField(primary_key=True, verbose_name='ID')
organisation_search = models.TextField(blank=True, null=True)
org_alpha_search = models.TextField(blank=True, null=True)
organisation_english = models.CharField(max_length=256, blank=True, null=True, verbose_name='Organisation')
organisation_2 = models.CharField(max_length=256, blank=True, null=True, verbose_name='Department 1')
organisation_3 = models.CharField(max_length=256, blank=True, null=True, verbose_name='Department 2')
organisation_english = models.CharField(
max_length=256, blank=True, null=True, verbose_name='Organisation')
organisation_2 = models.CharField(
max_length=256, blank=True, null=True, verbose_name='Department 1')
organisation_3 = models.CharField(
max_length=256, blank=True, null=True, verbose_name='Department 2')
organisation_original = models.TextField(blank=True, null=True)
acronym = models.CharField(max_length=128, blank=True, null=True)
street = models.CharField(max_length=256, blank=True, null=True)
@ -413,27 +433,33 @@ class Organisation(models.Model):
url = models.URLField(blank=True, null=True)
tel = models.CharField(max_length=128, blank=True, null=True)
email = models.EmailField(blank=True, null=True)
country = models.ForeignKey(Country, models.DO_NOTHING, blank=True, null=True, to_field='id')
country = models.ForeignKey(
Country, models.DO_NOTHING, blank=True, null=True, to_field='id')
tags = models.TextField(blank=True, null=True)
description = models.TextField(blank=True, null=True)
northing = models.TextField(blank=True, null=True)
easting = models.TextField(blank=True, null=True)
category = models.TextField(blank=True, null=True, choices=CATEGORY_CHOICES)
subject = models.CharField(max_length=128, blank=True, null=True, choices=SUBJECT_CHOICES)
category = models.TextField(
blank=True, null=True, choices=CATEGORY_CHOICES)
subject = models.CharField(
max_length=128, blank=True, null=True, choices=SUBJECT_CHOICES)
def __str__(self):
if self.organisation_english:
if self.organisation_2:
name = f"{self.organisation_english} ({self.organisation_2})"
name = f"{self.country} < {self.organisation_english} < {self.organisation_2} < {self.organisation_3} < {self.acronym}"
else:
name = f"{self.organisation_english}"
name = f"{self.country} < {self.organisation_english} < {self.organisation_2} < {self.organisation_3} < {self.acronym}"
else:
name = 'NO NAME DEFINED!!!'
name = ' ---'
return name
class RangeOnlineInfo(models.Model):
id = models.AutoField(primary_key=True)
# This is supposed to be linked to MountainRange via range_name_map, but the range_name_map
@ -450,8 +476,10 @@ class RangeOnlineInfo(models.Model):
class RangeNameTranslation(models.Model):
id = models.AutoField(primary_key=True)
range_name = models.ForeignKey(MountainRange, models.DO_NOTHING, blank=True, null=True)
language_translation = models.ForeignKey(Language, models.DO_NOTHING, blank=True, null=True)
range_name = models.ForeignKey(
MountainRange, models.DO_NOTHING, blank=True, null=True)
language_translation = models.ForeignKey(
Language, models.DO_NOTHING, blank=True, null=True)
range_name_translation = models.TextField(blank=True, null=True)
def __str__(self):
@ -504,8 +532,10 @@ class Keyword(models.Model):
class ResourceKeyword(models.Model):
id = models.AutoField(primary_key=True)
resource = models.ForeignKey(Resource, models.DO_NOTHING, blank=True, null=True)
keyword = models.ForeignKey(Keyword, models.DO_NOTHING, blank=True, null=True, to_field='keyword_id')
resource = models.ForeignKey(
Resource, models.DO_NOTHING, blank=True, null=True)
keyword = models.ForeignKey(
Keyword, models.DO_NOTHING, blank=True, null=True, to_field='keyword_id')
def __str__(self):
return '%s - %s' % (self.resource.title, self.keyword.keyword)
@ -528,8 +558,10 @@ class NamesImport(models.Model):
class ResourceRange(models.Model):
id = models.AutoField(primary_key=True)
resource_title = models.ForeignKey(Resource, models.DO_NOTHING, blank=True, null=True)
range_name = models.ForeignKey(MountainRange, models.DO_NOTHING, blank=True, null=True)
resource_title = models.ForeignKey(
Resource, models.DO_NOTHING, blank=True, null=True)
range_name = models.ForeignKey(
MountainRange, models.DO_NOTHING, blank=True, null=True)
def __str__(self):
return '%s, %s' % (self.resource_title.title, self.range_name.name)
@ -537,7 +569,8 @@ class ResourceRange(models.Model):
class LanguageLink(models.Model):
id = models.AutoField(primary_key=True)
language_number_code = models.ForeignKey(Language, models.DO_NOTHING, blank=True, null=True)
language_number_code = models.ForeignKey(
Language, models.DO_NOTHING, blank=True, null=True)
language_letter_code = models.TextField(blank=True, null=True)
def __str__(self):
@ -559,8 +592,10 @@ class Peak(models.Model):
class Search(models.Model):
id = models.AutoField(primary_key=True)
range_name = models.ForeignKey(MountainRange, models.DO_NOTHING, blank=True, null=True)
repository = models.ForeignKey(Repository, models.DO_NOTHING, blank=True, null=True)
range_name = models.ForeignKey(
MountainRange, models.DO_NOTHING, blank=True, null=True)
repository = models.ForeignKey(
Repository, models.DO_NOTHING, blank=True, null=True)
search_string = models.TextField(blank=True, null=True)
search_date = models.TextField(blank=True, null=True)
result = models.TextField(blank=True, null=True)
@ -575,9 +610,7 @@ class Person(models.Model):
MR_MRS_CHOICES = (
('', ''),
('Ms', 'Ms'),
('Ms.', 'Ms.'),
('Mr', 'Mr'),
('Mr.', 'Mr.'),
)
GMBA_FUNCTION_CHOICES = (
('', ''),
@ -585,12 +618,12 @@ class Person(models.Model):
('''Involved scientist
Steering committee''', '''Involved scientist
Steering committee'''),
('Network', 'Network'),
('Network', 'Network'),
('Newsletter only', 'Newsletter only'),
('''Steering committee
Involved scientist''', '''Steering committee
Involved scientist''')
)
)
id = models.AutoField(primary_key=True)
source_id = models.IntegerField(blank=True, null=True)
title = models.CharField(blank=True, null=True, max_length=255)
@ -601,7 +634,9 @@ Involved scientist''')
contact_email = models.EmailField(blank=True, null=True) # email_1
personal_url = models.URLField(blank=True, null=True) # url ?
biography = models.TextField(blank=True, null=True)
field_indexer = models.TextField(db_column='_indexer', blank=True, null=True) # Field renamed because it started with '_'.
# Field renamed because it started with '_'.
field_indexer = models.TextField(
db_column='_indexer', blank=True, null=True)
mr_mrs = models.TextField(blank=True, null=True, choices=MR_MRS_CHOICES)
full_name = models.CharField(blank=True, null=True, max_length=100)
@ -612,12 +647,16 @@ Involved scientist''')
mobile_number = models.CharField(blank=True, null=True, max_length=50)
url = models.URLField(blank=True, null=True)
field_of_expertise = models.TextField(blank=True, null=True)
status = models.ForeignKey(PeopleStatus, models.DO_NOTHING, blank=True, null=True, to_field='id')
status = models.ForeignKey(
PeopleStatus, models.DO_NOTHING, blank=True, null=True, to_field='id')
entry_date = models.TextField(blank=True, null=True)
gmba_function = models.TextField(blank=True, null=True, choices=GMBA_FUNCTION_CHOICES)
gmba_function = models.TextField(
blank=True, null=True, choices=GMBA_FUNCTION_CHOICES)
news_letter = models.BooleanField(default=False)
country = models.ForeignKey(Country, models.DO_NOTHING, blank=True, null=True, to_field='id')
organization = models.ForeignKey(Organisation, models.DO_NOTHING, blank=True, null=True)
country = models.ForeignKey(
Country, models.DO_NOTHING, blank=True, null=True, to_field='id')
organization = models.ForeignKey(
Organisation, models.DO_NOTHING, blank=True, null=True)
birds = models.BooleanField(default=False)
mammals = models.BooleanField(default=False)
reptiles = models.BooleanField(default=False)
@ -642,7 +681,8 @@ Involved scientist''')
assessment = models.BooleanField(default=False)
meta_analysis = models.BooleanField(default=False)
synthesis = models.BooleanField(default=False)
qualitative_ssm = models.BooleanField(default=False) #"Qualitative social science methods (interviews, surveys)"
# "Qualitative social science methods (interviews, surveys)"
qualitative_ssm = models.BooleanField(default=False)
genetic_analyses = models.BooleanField(default=False)
field_site = models.BooleanField(default=False)
transect = models.BooleanField(default=False)
@ -667,10 +707,18 @@ Involved scientist''')
return False
def index(self):
self.field_indexer = " ".join([
self.first_name, self.last_name, self.organisation, self.position, self.biography
])
return True
if self:
self.field_indexer = " ".join([
self.first_name if self and self.first_name else "",
self.last_name if self and self.last_name else "",
self.organisation if self and self.organisation else "",
self.position if self and self.position else "",
self.biography if self and self.biography else ""
] if self else "")
# self.save()
return True
else:
return False
def fullname(self):
return " ".join([self.title if self.title else '',
@ -692,11 +740,16 @@ Involved scientist''')
'biography': self.biography or '',
}
def save(self, *args, **kwargs):
self.index()
super(Person, self).save(*args, **kwargs)
class TaxaPeople(models.Model):
id = models.AutoField(primary_key=True)
person = models.ForeignKey(Person, models.CASCADE, blank=True, null=True)
taxon = models.ForeignKey('Taxon', models.DO_NOTHING, blank=True, null=True)
taxon = models.ForeignKey(
'Taxon', models.DO_NOTHING, blank=True, null=True)
class Meta:
db_table = 'taxa_people'
@ -708,7 +761,8 @@ class TaxaPeople(models.Model):
class RangesPeople(models.Model):
id = models.AutoField(primary_key=True)
person = models.ForeignKey(Person, models.CASCADE, blank=True, null=True)
range = models.ForeignKey(MountainRange, models.DO_NOTHING, blank=True, null=True)
range = models.ForeignKey(
MountainRange, models.DO_NOTHING, blank=True, null=True)
class Meta:
db_table = 'ranges_people'
@ -720,7 +774,8 @@ class RangesPeople(models.Model):
class ResourcesPeople(models.Model):
id = models.AutoField(primary_key=True)
person = models.ForeignKey(Person, models.CASCADE, blank=True, null=True)
resource = models.ForeignKey(Resource, models.CASCADE, blank=True, null=True)
resource = models.ForeignKey(
Resource, models.CASCADE, blank=True, null=True)
class Meta:
db_table = 'resources_people'
@ -731,7 +786,8 @@ class ResourcesPeople(models.Model):
class ScalesPeople(models.Model):
id = models.AutoField(primary_key=True)
person = models.ForeignKey(Person, models.DO_NOTHING, blank=True, null=True)
person = models.ForeignKey(
Person, models.DO_NOTHING, blank=True, null=True)
scale = models.ForeignKey(Scale, models.DO_NOTHING, blank=True, null=True)
class Meta:
@ -755,7 +811,8 @@ class Species(models.Model):
class PeopleFunction(models.Model):
id = models.AutoField(primary_key=True)
person = models.ForeignKey(Person, models.CASCADE, blank=True, null=True)
function = models.ForeignKey(GMBA_function, models.DO_NOTHING, blank=True, null=True)
function = models.ForeignKey(
GMBA_function, models.DO_NOTHING, blank=True, null=True)
def __str__(self):
return self.person.full_name
@ -763,8 +820,10 @@ class PeopleFunction(models.Model):
class SpeciesRange(models.Model):
id = models.AutoField(primary_key=True)
scientific_name = models.ForeignKey(Species, models.DO_NOTHING, blank=True, null=True)
range = models.ForeignKey(MountainRange, models.DO_NOTHING, blank=True, null=True)
scientific_name = models.ForeignKey(
Species, models.DO_NOTHING, blank=True, null=True)
range = models.ForeignKey(
MountainRange, models.DO_NOTHING, blank=True, null=True)
endemic = models.TextField(blank=True, null=True)
source_url = models.TextField(blank=True, null=True)
@ -775,7 +834,8 @@ class SpeciesRange(models.Model):
class PeopleRange(models.Model):
id = models.AutoField(primary_key=True)
person = models.ForeignKey(Person, models.CASCADE, blank=True, null=True)
range = models.ForeignKey(MountainRange, models.DO_NOTHING, blank=True, null=True)
range = models.ForeignKey(
MountainRange, models.DO_NOTHING, blank=True, null=True)
def __str__(self):
return str(self.id)
@ -783,7 +843,8 @@ class PeopleRange(models.Model):
class TaxonRange(models.Model):
id = models.AutoField(primary_key=True)
range = models.ForeignKey(MountainRange, models.DO_NOTHING, blank=True, null=True)
range = models.ForeignKey(
MountainRange, models.DO_NOTHING, blank=True, null=True)
taxon = models.TextField(blank=True, null=True)
subrange_or_region = models.TextField(blank=True, null=True)
taxon_status = models.TextField(blank=True, null=True)
@ -814,7 +875,8 @@ class PeopleResource(models.Model):
)
id = models.AutoField(primary_key=True)
person = models.ForeignKey(Person, models.CASCADE, blank=True, null=True)
resource = models.ForeignKey(Resource, models.DO_NOTHING, blank=True, null=True)
resource = models.ForeignKey(
Resource, models.DO_NOTHING, blank=True, null=True)
role = models.TextField(blank=True, null=True, choices=ROLES_CHOICES)
def __str__(self):
@ -823,8 +885,10 @@ class PeopleResource(models.Model):
class RangeCountry(models.Model):
id = models.AutoField(primary_key=True)
range = models.ForeignKey(MountainRange, models.DO_NOTHING, blank=True, null=True)
country = models.ForeignKey(Country, models.DO_NOTHING, blank=True, null=True)
range = models.ForeignKey(
MountainRange, models.DO_NOTHING, blank=True, null=True)
country = models.ForeignKey(
Country, models.DO_NOTHING, blank=True, null=True)
def __str__(self):
return '%s --- %s' % (self.range.range_name if self.range else 'None', self.country.short_name if self.country else 'None')

View File

@ -248,7 +248,7 @@
</div><!-- /person-tags -->
<a name="contact"></a><h3>Contact</h3>
<form action="https://formspree.io/&#103;&#109;&#098;&#097;&#064;&#105;&#112;&#115;&#046;&#117;&#110;&#105;&#098;&#101;&#046;&#099;&#104;"
<form onsubmit="{ FormSubmitted }" action="https://formspree.io/f/xvolqjpe"
target="_blank" method="POST" class="contact-form">
<input type="hidden" name="subject" value="Contact request from GMBA Connect">
<input type="hidden" name="person" value={ person.data.fullname }>
@ -256,7 +256,7 @@
<input type="text" name="name" placeholder="Your name" required>
<input type="email" name="_replyto" placeholder="E-mail address" required>
<p>
<input type="submit" value="Send" class="c-button u-small c-button--brand">
<input type="submit" value="Send" class="c-button u-small c-button--brand">
</p>
</form>
@ -287,6 +287,12 @@
const FILTER_BLANK = {
'country': [], 'range': [], 'field': [], 'taxon': []
}
FormSubmitted(){
console.log("i got executed")
var self = this
self.closedetails()
}
this.filters_shown = FILTER_BLANK
search(e, nextpage) {
@ -481,6 +487,9 @@
}
})
</script>
</gmba-search>

View File

@ -9,6 +9,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="">
<meta name="referrer" content="origin">
<link href="{% static 'app/admin/bootstrap/bootstrap3/swatch/default/bootstrap.min.css' %}?v=3.3.5" rel="stylesheet">

View File

@ -6,6 +6,8 @@
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="referrer" content="origin">
<!--[if lte IE 8]><script src="/static/assets/js/ie/html5shiv.js"></script><![endif]-->
<!--[if lte IE 8]><link rel="stylesheet" href="/static/assets/css/ie8.css" /><![endif]-->

View File

@ -5,6 +5,8 @@
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="referrer" content="origin">
<!--[if lte IE 8]><script src="{% static 'app/assets/js/ie/html5shiv.js' %}"></script><![endif]-->
<!--[if lte IE 8]><link rel="stylesheet" href="{% static 'app/assets/ss/ie8.css' %}" /><![endif]-->

View File

@ -176,11 +176,17 @@ def get_paginated(query_set, page, per_page):
for p in paginator.object_list:
filters['country'].append(p.country.short_name)
for r in p.peoplerange_set.all():
filters['range'].append(r.range.range_name)
if r.range and r.range.range_name:
filters['range'].append(r.range.range_name)
else:
print("r.range.range_name is None %s %s" % (r.range_id, r.person_id))
for r in p.fieldspeople_set.all():
filters['field'].append(r.field.name)
for r in p.taxapeople_set.all():
filters['taxon'].append(r.taxon.name)
if r and r.taxon and r.taxon.name:
filters['taxon'].append(r.taxon.name)
else:
print("r.taxon.name is None %s %s" % (r.range_id, r.taxon))
filters = {
'country': sorted(set(filters['country'])),
'range': sorted(set(filters['range'])),
@ -207,10 +213,10 @@ class SearchView(View):
per_page = int(self.request.GET.get('per_page', 10))
q = self.request.GET.get('q', '').strip()
if not q or len(q) < 3:
query_set = Person.objects.all()
query_set = Person.objects.filter(profile_on_web=True).all()
else:
query = reduce(operator.or_, (Q(field_indexer__icontains=item) for item in q.split(" ")))
query_set = Person.objects.filter(query)
query_set = Person.objects.filter(query).filter(profile_on_web=True)
q_country = self.request.GET.get('country', '')
q_range = self.request.GET.get('range', '')
@ -219,7 +225,7 @@ class SearchView(View):
if len(q_country) > 2:
query_set = query_set.filter(country__short_name__icontains=q_country.strip().lower())
if len(q_range) > 2:
ranges_people = PeopleRange.objects.filter(range__name__icontains=q_range.strip().lower())
ranges_people = PeopleRange.objects.filter(range__range_name__icontains=q_range.strip().lower())
r_people_ids = [rp.person_id for rp in ranges_people]
query_set = query_set.filter(id__in=r_people_ids)
if len(q_field) > 2:
@ -239,8 +245,8 @@ class PeopleDetailView(View):
person = get_object_or_404(Person, id=people_id)
return_data = {
'data': person.dict(),
'resources': [r.resource.dict() for r in person.resourcespeople_set.all()],
'ranges': [r.range.dict() for r in person.rangespeople_set.all()],
'resources': [r.resource.dict() for r in person.peopleresource_set.all()],
'ranges': [r.range.dict() for r in person.peoplerange_set.all()],
'fields': [r.field.name for r in person.fieldspeople_set.all()],
'methods': [r.method.name for r in person.methodspeople_set.all()],
'scales': [r.scale.name for r in person.scalespeople_set.all()],

37
docker-compose.prod.yml Normal file
View File

@ -0,0 +1,37 @@
version: '3.8'
services:
web:
build:
context: ./
dockerfile: Dockerfile.prod
command: gunicorn gmba_django.wsgi:application --bind [::]:8000
volumes:
- static_volume:/data/app/app/static
- media_volume:/data/app/app/media
expose:
- 8000
env_file:
- ./.env.prod
depends_on:
- db
db:
image: postgres:13.0-alpine
volumes:
- postgres_data:/data/var/lib/postgresql/data/
env_file:
- ./.env.prod
nginx:
build: ./nginx
volumes:
- static_volume:/data/app/app/static
- media_volume:/data/app/app/media
ports:
- 1337:80
depends_on:
- web
volumes:
postgres_data:
static_volume:
media_volume:

15
entrypoint.prod.sh Executable file
View File

@ -0,0 +1,15 @@
#!/bin/sh
if [ "$DATABASE" = "postgres" ]
then
echo "Waiting for postgres..."
while ! nc -z $SQL_HOST $SQL_PORT; do
sleep 0.1
done
echo "PostgreSQL started"
fi
exec "$@"

View File

@ -118,3 +118,5 @@ STATIC_URL = '/static/'
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
ADMIN_LIST_PER_PAGE = os.getenv('ADMIN_LIST_PER_PAGE', 20)

View File

@ -4,7 +4,11 @@ DEBUG = True
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
'ENGINE': os.environ.get('SQL_ENGINE', 'django.db.backends.postgresql'),
'NAME': os.environ.get('POSTGRES_DB', 'app'),
'USER': os.environ.get('POSTGRES_USER', 'app'),
'PASSWORD': os.environ.get('POSTGRES_PASSWORD', ''),
'HOST': os.environ.get('POSTGRES_HOST', 'localhost'),
'PORT': os.environ.get('POSTGRES_PORT', 5432),
}
}
}

View File

@ -6,17 +6,20 @@ ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', "").split(",")
DATABASES = {
'default': {
'ENGINE': os.environ.get('SQL_ENGINE', 'django.db.backends.sqlite3'),
'NAME': os.environ.get('SQL_DATABASE', os.path.join(BASE_DIR, 'db.sqlite3')),
# 'USER': os.environ.get('SQL_USER', 'user'),
# 'PASSWORD': os.environ.get('SQL_PASSWORD', 'password'),
# 'HOST': os.environ.get('SQL_HOST', 'localhost'),
# 'PORT': os.environ.get('SQL_PORT', ''),
'ENGINE': os.environ.get('SQL_ENGINE', 'django.db.backends.postgresql'),
'NAME': os.environ.get('POSTGRES_DB', 'app'),
'USER': os.environ.get('POSTGRES_USER', 'app'),
'PASSWORD': os.environ.get('POSTGRES_PASSWORD', ''),
'HOST': os.environ.get('POSTGRES_HOST', 'localhost'),
'PORT': os.environ.get('POSTGRES_PORT', 5432),
}
}
SECURE_SSL_REDIRECT = True
# See https://docs.djangoproject.com/en/2.2/ref/settings/#secure-proxy-ssl-header
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True

6
init.sh Executable file
View File

@ -0,0 +1,6 @@
#!/bin/ash
#python manage.py migrate
python manage.py collectstatic --noinput
#
#gunicorn gmba_django.wsgi:application --bind [::]:8000

4
nginx/Dockerfile Normal file
View File

@ -0,0 +1,4 @@
FROM nginx:1.21-alpine
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/conf.d

28
nginx/nginx.conf Normal file
View File

@ -0,0 +1,28 @@
upstream gmba_django {
server web:8000;
}
server {
listen 80;
client_max_body_size 256m;
location / {
proxy_pass http://gmba_django;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
location /static/ {
alias /home/app/app/static/;
expires max;
}
location /media/ {
alias /home/app/app/media/;
expires max;
}
add_header Content-Security-Policy "frame-ancestors https://www.gmba.unibe.ch";
}

View File

@ -1,8 +1,9 @@
asgiref==3.4.1
Django==3.2.5
Django==4.0.1
python-dotenv==0.19.0
pytz==2021.1
sqlparse==0.4.1
typing-extensions==3.10.0.0
psycopg2==2.9.1
Werkzeug==2.0.2
gunicorn==20.1.0