diff --git a/.env.sample b/.env.sample
index 71583f9d..6c40dddc 100644
--- a/.env.sample
+++ b/.env.sample
@@ -7,8 +7,8 @@ HOSTNAME=localhost:8000
CSRF_COOKIE_DOMAIN=.mysite.com
# Postgres database credentials
-DB_NAME=webapp
-DB_USER=webapp
+DB_NAME=gms
+DB_USER=gms
DB_PASSWORD="secret"
# Credentials for your SMTP mail server
@@ -16,6 +16,9 @@ MAIL_FROM_ADDRESS=noreply@mysite.com
MAIL_TO_ADDRESS=helpdesk@mysite.com
MAIL_USE_TLS=true
+# Optional: Send error emails to a different address than MAIL_FROM_ADDRESS
+SERVER_EMAIL=support@mysite.com
+
MAIL_SMTP_PORT=25
MAIL_HOSTNAME=mail.mysite.com
MAIL_SMTP_USERNAME=admin
diff --git a/.github/workflows/deploy-dev.yml b/.github/workflows/deploy-dev.yml
index 0861a78b..2747f985 100644
--- a/.github/workflows/deploy-dev.yml
+++ b/.github/workflows/deploy-dev.yml
@@ -23,6 +23,6 @@ jobs:
echo "${{ secrets.SSH_PRIVATE_KEY_DEV }}" > ~/.ssh/id_rsa
ssh-keyscan -H ${{ secrets.SSH_HOST_DEV }} > ~/.ssh/known_hosts
- name: connect and pull
- run: ssh ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST_DEV }} "./update.sh && exit"
+ run: ssh ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST_DEV }} "sudo ./update.sh && exit"
- name: cleanup
run: rm -rf ~/.ssh
diff --git a/deploy/ansible/.gitignore b/deploy/ansible/.gitignore
index a4d3d49a..793cd85d 100644
--- a/deploy/ansible/.gitignore
+++ b/deploy/ansible/.gitignore
@@ -1,2 +1,2 @@
roles/*
-!roles/webapp
\ No newline at end of file
+!roles/galaxy_media_site
\ No newline at end of file
diff --git a/deploy/ansible/README.md b/deploy/ansible/README.md
index f5a501b0..649902ec 100644
--- a/deploy/ansible/README.md
+++ b/deploy/ansible/README.md
@@ -37,7 +37,7 @@ python -m pip install ansible
- *Optional* - Host installation paths:
- `project_root` - where this git repository will be cloned
- `server_root` - where server configuration will be saved
- - `web_root` - where the application will be served from
+ - `django_root` - where the application will be served from
- `venv_root` - where the virtual env will be created
diff --git a/deploy/ansible/dev.yml b/deploy/ansible/dev.yml
index 2664227b..d3f28a96 100644
--- a/deploy/ansible/dev.yml
+++ b/deploy/ansible/dev.yml
@@ -6,7 +6,10 @@
- group_vars/secrets.yml
- group_vars/webservers.yml
roles:
- - geerlingguy.nginx
+ - role: geerlingguy.nginx
+ tags: init
- role: geerlingguy.postgresql
become: true
- - webapp
+ tags: init,postgresql
+ - role: galaxy_media_site
+ tags: gms
diff --git a/deploy/ansible/files/webapp.socket b/deploy/ansible/files/webapp.socket
index 4eb3bbe1..094d1e5c 100644
--- a/deploy/ansible/files/webapp.socket
+++ b/deploy/ansible/files/webapp.socket
@@ -1,6 +1,6 @@
[Unit]
Description=Galaxy content site socket
[Socket]
-ListenStream=/run/webapp.sock
+ListenStream=/run/gms.sock
[Install]
WantedBy=sockets.target
diff --git a/deploy/ansible/group_vars/webservers.yml b/deploy/ansible/group_vars/webservers.yml
index 42630787..35488d7f 100644
--- a/deploy/ansible/group_vars/webservers.yml
+++ b/deploy/ansible/group_vars/webservers.yml
@@ -16,8 +16,8 @@ gunicorn:
web_workers: 4
# Postgres database conf
-postgres_db_name: webapp
-postgres_db_user: webapp
+postgres_db_name: gms
+postgres_db_user: gms
postgresql_locales:
- 'en_US.UTF-8'
@@ -30,6 +30,7 @@ postgresql_users:
- name: "{{ postgres_db_user }}"
password: "{{ postgres_db_password }}"
db: "{{ postgres_db_name }}"
+ priv: ALL
postgres_users_no_log: false
@@ -37,18 +38,18 @@ postgres_users_no_log: false
# -----------------------------------------------------------------------------
# Will git clone galaxy-content-site to here
-project_root: /home/ubuntu/galaxy-content-site
+project_root: /srv/sites/galaxy-media-site
# This is where service files will be created
-server_root: /home/ubuntu/serve
+server_root: /srv/config
# App will be served from here
-web_root: /srv/webapp
+django_root: "{{ project_root }}/webapp"
# Virtual environment will be created here
-venv_root: "{{ project_root }}/.venv"
+venv_root: "{{ project_root }}/venv"
-# Admin user login for the admin portal
+# Login for django admin portal
admin_user:
first_name: admin
last_name: admin
diff --git a/deploy/ansible/group_vars/webservers.yml.sample b/deploy/ansible/group_vars/webservers.yml.sample
index 8ec68d6c..aa1ecb17 100644
--- a/deploy/ansible/group_vars/webservers.yml.sample
+++ b/deploy/ansible/group_vars/webservers.yml.sample
@@ -19,8 +19,8 @@ gunicorn:
web_workers: 4
# Postgres database conf
-postgres_db_name: webapp
-postgres_db_user: webapp
+postgres_db_name: gms
+postgres_db_user: gms
postgresql_locales:
- 'en_US.UTF-8'
@@ -46,7 +46,7 @@ project_root: /home/ubuntu/galaxy-content-site
server_root: /home/ubuntu/serve
# App will be served from here
-web_root: /srv/webapp
+django_root: /srv/webapp
# Virtual environment will be created here
venv_root: "{{ project_root }}/.venv"
diff --git a/deploy/ansible/host_vars/site.usegalaxy.org.au.yml b/deploy/ansible/host_vars/site.usegalaxy.org.au.yml
deleted file mode 100644
index edaf9995..00000000
--- a/deploy/ansible/host_vars/site.usegalaxy.org.au.yml
+++ /dev/null
@@ -1 +0,0 @@
-hostname: usegalaxy-au.neoformit.com
diff --git a/deploy/ansible/hosts b/deploy/ansible/hosts
index 52e97fbb..c99064c0 100644
--- a/deploy/ansible/hosts
+++ b/deploy/ansible/hosts
@@ -1,5 +1,5 @@
[webservers]
-site.usegalaxy.org.au ansible_connection=ssh ansible_user=ubuntu
+site.usegalaxy.org.au ansible_connection=ssh ansible_user=ubuntu ansible_ssh_private_key_file=~/.ssh/galaxy
[dev_webservers]
-dev-site.gvl.org.au ansible_connection=ssh ansible_user=ubuntu
+dev-site.gvl.org.au ansible_connection=ssh ansible_user=ubuntu ansible_ssh_private_key_file=~/.ssh/galaxy
diff --git a/deploy/ansible/prod.yml b/deploy/ansible/prod.yml
index 938695bb..8c74c6d3 100644
--- a/deploy/ansible/prod.yml
+++ b/deploy/ansible/prod.yml
@@ -6,7 +6,10 @@
- group_vars/secrets.yml
- group_vars/webservers.yml
roles:
- - geerlingguy.nginx
+ - role: geerlingguy.nginx
+ tags: init
- role: geerlingguy.postgresql
become: true
- - webapp
+ tags: init,postgresql
+ - role: galaxy_media_site
+ tags: gms
diff --git a/deploy/ansible/roles/webapp/defaults/main.yml b/deploy/ansible/roles/galaxy_media_site/defaults/main.yml
similarity index 67%
rename from deploy/ansible/roles/webapp/defaults/main.yml
rename to deploy/ansible/roles/galaxy_media_site/defaults/main.yml
index edcbd089..f1127c1e 100644
--- a/deploy/ansible/roles/webapp/defaults/main.yml
+++ b/deploy/ansible/roles/galaxy_media_site/defaults/main.yml
@@ -1,15 +1,15 @@
---
-project_root: /home/ubuntu/galaxy-content-site
-server_root: /home/ubuntu/server
-web_root: /srv/webapp
+project_root: /srv/galaxy-media-site
+server_root: /srv/config
+django_root: "{{ project_root }}/webapp"
venv_root: "{{ project_root }}/venv"
-webapp:
+gms:
templates:
- src: "{{ role_path }}/templates/gunicorn.py.j2"
dest: "{{ server_root }}/gunicorn.py"
- - src: "{{ role_path }}/templates/webapp.service.j2"
- dest: /etc/systemd/system/webapp.service
+ - src: "{{ role_path }}/templates/gms.service.j2"
+ dest: /etc/systemd/system/gms.service
- src: "{{ role_path }}/templates/setup.sh.j2"
dest: "{{ server_root }}/setup.sh"
- src: "{{ role_path }}/templates/nginx.vhost.j2"
@@ -20,8 +20,8 @@ webapp:
dest: "/home/ubuntu/update.sh"
files:
- - src: "{{ role_path }}/files/webapp.socket"
- dest: /etc/systemd/system/webapp.socket
+ - src: "{{ role_path }}/files/gms.socket"
+ dest: /etc/systemd/system/gms.socket
certbot_ssl: true
diff --git a/deploy/ansible/roles/webapp/files/webapp.socket b/deploy/ansible/roles/galaxy_media_site/files/gms.socket
similarity index 74%
rename from deploy/ansible/roles/webapp/files/webapp.socket
rename to deploy/ansible/roles/galaxy_media_site/files/gms.socket
index 4eb3bbe1..094d1e5c 100644
--- a/deploy/ansible/roles/webapp/files/webapp.socket
+++ b/deploy/ansible/roles/galaxy_media_site/files/gms.socket
@@ -1,6 +1,6 @@
[Unit]
Description=Galaxy content site socket
[Socket]
-ListenStream=/run/webapp.sock
+ListenStream=/run/gms.sock
[Install]
WantedBy=sockets.target
diff --git a/deploy/ansible/roles/webapp/tasks/main.yml b/deploy/ansible/roles/galaxy_media_site/tasks/main.yml
similarity index 64%
rename from deploy/ansible/roles/webapp/tasks/main.yml
rename to deploy/ansible/roles/galaxy_media_site/tasks/main.yml
index ac5f719e..03335ba1 100644
--- a/deploy/ansible/roles/webapp/tasks/main.yml
+++ b/deploy/ansible/roles/galaxy_media_site/tasks/main.yml
@@ -1,5 +1,15 @@
---
+- name: Check whether SSL certificate is already installed
+ ansible.builtin.shell: "certbot certificates"
+ register: certbot_certificates
+ changed_when: false
+
+- name: Set ssl_cert_exists fact from certbot output
+ ansible.builtin.set_fact:
+ ssl_cert_exists: "{{ true if inventory_hostname in certbot_certificates.stdout else false }}"
+ changed_when: false
+
- name: create server directory
file:
path: "{{ server_root }}"
@@ -19,11 +29,19 @@
name:
- gcc
- python3.12
- - python3.12-pip
- - python3.12-venv
+ - python3-pip
+ - python3-virtualenv
- python3.12-dev
- python3-certbot-nginx
+- name: Grant database privileges to postgres_db_user
+ ansible.builtin.shell: >
+ sudo -u postgres psql -c
+ "GRANT ALL ON SCHEMA public TO {{ postgres_db_user }};
+ GRANT USAGE, CREATE ON SCHEMA public TO {{ postgres_db_user }};
+ ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO gms;"
+ become: yes
+
- name: clone git repository for galaxy-content-site
ansible.builtin.git:
repo: https://github.com/neoformit/galaxy-content-site.git
@@ -31,33 +49,27 @@
clone: yes
force: yes
-- name: link webapp to /srv/sites
- ansible.builtin.file:
- src: "{{ project_root }}/webapp"
- dest: "{{ web_root }}"
- state: link
-
-- name: create webapp media directory
+- name: create gms media directory
file:
- path: "{{ web_root }}/webapp/media"
+ path: "{{ django_root }}/webapp/media"
state: directory
-- name: create webapp logs directory
+- name: create gms logs directory
file:
- path: "{{ web_root }}/webapp/logs"
+ path: "{{ django_root }}/webapp/logs"
state: directory
- name: template webserver configuration
template:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
- loop: "{{ webapp.templates }}"
+ loop: "{{ gms.templates }}"
- name: copy webserver configuration
copy:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
- loop: "{{ webapp.files }}"
+ loop: "{{ gms.files }}"
- name: link to enable nginx virtualhost
ansible.builtin.file:
@@ -71,16 +83,16 @@
virtualenv: "{{ venv_root }}"
virtualenv_python: python3.12
-- name: run webapp setup script
+- name: run gms setup script
command: "bash {{ server_root }}/setup.sh"
- name: create and install SSL certificate with letsencrypt
command: "certbot --nginx --noninteractive --agree-tos --redirect --email {{ certbot_renew_email }} -d {{ inventory_hostname }}"
when: certbot_ssl
-- name: Ensure webapp superuser login
+- name: Ensure gms superuser login
shell: |
- cd {{ web_root }} && \
+ cd {{ django_root }} && \
export DJANGO_SUPERUSER_PASSWORD={{ admin_user.password }} && \
{{ venv_root }}/bin/python manage.py createsuperuser --noinput \
--email {{ admin_user.email }} \
@@ -98,10 +110,10 @@
group: ubuntu
- name: update media file ownership
- file: dest={{ web_root }}/webapp/media owner=www-data group=www-data mode=u=rwX,g=rwX,o=rwX recurse=yes
+ file: dest={{ django_root }}/webapp/media owner=www-data group=www-data mode=u=rwX,g=rwX,o=rwX recurse=yes
- name: update log file ownership
- file: dest={{ web_root }}/webapp/logs owner=www-data group=www-data mode=u=rwX,g=rwX,o=rwX recurse=yes
+ file: dest={{ django_root }}/webapp/logs owner=www-data group=www-data mode=u=rwX,g=rwX,o=rwX recurse=yes
- name: make update.sh executable
file: dest=/home/ubuntu/update.sh mode=a+x
@@ -109,7 +121,7 @@
- name: check whether news scraper in GMS version
ansible.builtin.shell: "{{ venv_root }}/bin/python manage.py scrape_news --help"
args:
- chdir: "{{ web_root }}"
+ chdir: "{{ django_root }}"
register: check_scraper
- name: add cron job to scrape news feed
@@ -118,5 +130,5 @@
user: ubuntu
hour: 9
minute: 0
- job: "cd {{ web_root }} && {{ venv_root }}/bin/python manage.py scrape_news"
+ job: "cd {{ django_root }} && {{ venv_root }}/bin/python manage.py scrape_news"
when: check_scraper.rc == 0
diff --git a/deploy/ansible/roles/webapp/templates/.env.j2 b/deploy/ansible/roles/galaxy_media_site/templates/.env.j2
similarity index 100%
rename from deploy/ansible/roles/webapp/templates/.env.j2
rename to deploy/ansible/roles/galaxy_media_site/templates/.env.j2
diff --git a/deploy/ansible/roles/webapp/templates/webapp.service.j2 b/deploy/ansible/roles/galaxy_media_site/templates/gms.service.j2
similarity index 73%
rename from deploy/ansible/roles/webapp/templates/webapp.service.j2
rename to deploy/ansible/roles/galaxy_media_site/templates/gms.service.j2
index 03dbb852..97947793 100644
--- a/deploy/ansible/roles/webapp/templates/webapp.service.j2
+++ b/deploy/ansible/roles/galaxy_media_site/templates/gms.service.j2
@@ -1,6 +1,6 @@
[Unit]
Description=Gunicorn for Galaxy Media Site
-Requires=webapp.socket
+Requires=gms.socket
After=network.target
[Service]
@@ -8,10 +8,10 @@ PIDFile=/run/gunicorn/pid
User = www-data
Group = www-data
RuntimeDirectory=gunicorn
-WorkingDirectory={{ web_root }}
-Environment="PATH={{ venv_root }}/.venv/bin:$PATH"
+WorkingDirectory={{ django_root }}
+Environment="PATH={{ venv_root }}/bin:$PATH"
ExecStart={{ venv_root }}/bin/gunicorn --pid /run/gunicorn/pid \
- --bind unix:/run/webapp.sock \
+ --bind unix:/run/gms.sock \
-c {{ server_root }}/gunicorn.py webapp.wsgi
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID
diff --git a/deploy/ansible/roles/webapp/templates/gunicorn.py.j2 b/deploy/ansible/roles/galaxy_media_site/templates/gunicorn.py.j2
similarity index 100%
rename from deploy/ansible/roles/webapp/templates/gunicorn.py.j2
rename to deploy/ansible/roles/galaxy_media_site/templates/gunicorn.py.j2
diff --git a/deploy/ansible/roles/galaxy_media_site/templates/nginx.vhost.j2 b/deploy/ansible/roles/galaxy_media_site/templates/nginx.vhost.j2
new file mode 100644
index 00000000..2acdde20
--- /dev/null
+++ b/deploy/ansible/roles/galaxy_media_site/templates/nginx.vhost.j2
@@ -0,0 +1,71 @@
+# Server config for {{ inventory_hostname }} (Galaxy media site)
+
+server {
+ # redirect www to non-www
+ server_name www.{{ inventory_hostname }};
+ return 301 $scheme://{{ inventory_hostname }}$request_uri;
+}
+
+
+server {
+
+ listen 80;
+ server_name {{ inventory_hostname }};
+ access_log /var/log/nginx/gms.access.log;
+ error_log /var/log/nginx/gms.error.log;
+
+ if ( $host !~* ^({{ inventory_hostname }})$ ) {
+ # Reject requests with incorrect host header
+ return 444;
+ }
+
+ location = /biconcave {
+ return 404;
+ }
+
+ location = /favicon.ico {
+ alias {{ django_root }}/webapp/static/favicon/favicon.ico;
+ }
+
+ location /static {
+ root {{ django_root }}/webapp;
+ }
+
+ location /media {
+ root {{ django_root }}/webapp;
+ }
+
+ location / {
+ proxy_pass http://unix:/run/gms.sock;
+ proxy_redirect off;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_hide_header X-Frame-Options;
+ proxy_read_timeout 600; # seconds
+ client_max_body_size 1000m;
+ }
+
+ {% if ssl_cert_exists %}
+ listen 443 ssl; # managed by Certbot
+ ssl_certificate /etc/letsencrypt/live/gms.neoformit.com/fullchain.pem; # managed by Certbot
+ ssl_certificate_key /etc/letsencrypt/live/gms.neoformit.com/privkey.pem; # managed by Certbot
+ include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
+ ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
+ {% endif %}
+
+}
+
+{% if ssl_cert_exists %}
+server {
+
+ if ($host = gms.neoformit.com) {
+ return 301 https://$host$request_uri;
+ } # managed by Certbot
+
+ listen 80;
+ server_name gms.neoformit.com;
+ return 404; # managed by Certbot
+
+}
+{% endif %}
diff --git a/deploy/ansible/roles/webapp/templates/setup.sh.j2 b/deploy/ansible/roles/galaxy_media_site/templates/setup.sh.j2
similarity index 66%
rename from deploy/ansible/roles/webapp/templates/setup.sh.j2
rename to deploy/ansible/roles/galaxy_media_site/templates/setup.sh.j2
index e361f906..eae35408 100644
--- a/deploy/ansible/roles/webapp/templates/setup.sh.j2
+++ b/deploy/ansible/roles/galaxy_media_site/templates/setup.sh.j2
@@ -1,23 +1,23 @@
-# Set up webapp and restart web services
+# Set up gms and restart web services
set -e
source {{ venv_root }}/bin/activate
-cd {{ project_root }}/webapp
+cd {{ django_root }}
# Set Django settings
export DJANGO_SETTINGS_MODULE=webapp.settings.prod
+# Collect static files for Nginx
+python manage.py collectstatic --noinput
+
{% if not skip_database_migration %}
# Migrate database
python manage.py migrate
{% endif %}
-# Collect static files for Nginx
-python manage.py collectstatic --noinput
-
# Restart services
sudo systemctl daemon-reload
-sudo systemctl enable webapp.service
-sudo systemctl enable webapp.socket
-sudo service webapp restart
+sudo systemctl enable gms.service
+sudo systemctl enable gms.socket
+sudo service gms restart
diff --git a/deploy/ansible/roles/webapp/templates/update.sh.j2 b/deploy/ansible/roles/galaxy_media_site/templates/update.sh.j2
similarity index 65%
rename from deploy/ansible/roles/webapp/templates/update.sh.j2
rename to deploy/ansible/roles/galaxy_media_site/templates/update.sh.j2
index 8a2d8bb7..b0296552 100644
--- a/deploy/ansible/roles/webapp/templates/update.sh.j2
+++ b/deploy/ansible/roles/galaxy_media_site/templates/update.sh.j2
@@ -4,18 +4,18 @@
set -e
-# Make sure this isn't being run as root
-if [[ $EUID = 0 ]]; then
- echo "Don't run this as root - ubuntu is fine!"
+# Ensure run as root
+if [[ $EUID != 0 ]]; then
+ echo "Must be run as root - use sudo"
exit 0
fi
# Source virtual environment and git pull
-cd galaxy-content-site
+cd {{ project_root }}
source '{{ venv_root }}/bin/activate'
git pull
python -m pip install -r requirements.txt
-cd webapp
+cd {{ django_root }}
# Collect any new static files for Nginx if neccessary
python manage.py collectstatic --noinput
@@ -24,11 +24,11 @@ python manage.py collectstatic --noinput
python manage.py migrate
# Update file ownership to allow www-data to write logs/media
-sudo chown -R www-data:www-data webapp/logs
-sudo chown -R www-data:www-data webapp/media
+chown -R www-data:www-data webapp/logs
+chown -R www-data:www-data webapp/media
# Restart the GMS web service
-sudo service webapp restart
+service gms restart
echo ""
echo "~~~ Restarted Galaxy Media Site ~~~"
diff --git a/deploy/ansible/roles/webapp/templates/nginx.vhost.j2 b/deploy/ansible/roles/webapp/templates/nginx.vhost.j2
deleted file mode 100644
index 7ee21fbc..00000000
--- a/deploy/ansible/roles/webapp/templates/nginx.vhost.j2
+++ /dev/null
@@ -1,49 +0,0 @@
-# Server config for {{ inventory_hostname }} (Galaxy content site)
-
-server {
- # redirect www to non-www
- server_name www.{{ inventory_hostname }};
- return 301 $scheme://{{ inventory_hostname }}$request_uri;
-}
-
-
-server {
-
- listen 80;
- server_name {{ inventory_hostname }};
- access_log /var/log/nginx/webapp.access.log;
- error_log /var/log/nginx/webapp.error.log;
-
- if ( $host !~* ^({{ inventory_hostname }})$ ) {
- # Reject requests with incorrect host header
- return 444;
- }
-
- location = /biconcave {
- return 404;
- }
-
- location = /favicon.ico {
- alias {{ web_root }}/webapp/static/favicon/favicon.ico;
- }
-
- location /static {
- root {{ web_root }}/webapp;
- }
-
- location /media {
- root {{ web_root }}/webapp;
- }
-
- location / {
- proxy_pass http://unix:/run/webapp.sock;
- proxy_redirect off;
- proxy_set_header Host $host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_hide_header X-Frame-Options;
- proxy_read_timeout 600; # seconds
- client_max_body_size 1000m;
- }
-
-}
diff --git a/deploy/nginx.conf.tmpl b/deploy/nginx.conf.tmpl
index ce9702f4..bfd29130 100644
--- a/deploy/nginx.conf.tmpl
+++ b/deploy/nginx.conf.tmpl
@@ -11,8 +11,8 @@ server {
listen 80;
server_name {{ HOSTNAME }};
- access_log /var/log/nginx/webapp.access.log;
- error_log /var/log/nginx/webapp.error.log;
+ access_log /var/log/nginx/gms.access.log;
+ error_log /var/log/nginx/gms.error.log;
if ( $host !~* ^({{ HOSTNAME }})$ ) {
# Reject requests with incorrect host header
@@ -24,19 +24,19 @@ server {
}
location = /favicon.ico {
- alias /srv/sites/webapp/webapp/static/favicon/favicon.ico;
+ alias /srv/galaxy-media-site/webapp/gms/static/favicon/favicon.ico;
}
location /static {
- root /srv/sites/webapp/webapp;
+ root /srv/galaxy-media-site/webapp/gms;
}
location /media {
- root /srv/sites/webapp/webapp;
+ root /srv/galaxy-media-site/webapp/gms;
}
location / {
- proxy_pass http://unix:/run/webapp.sock;
+ proxy_pass http://unix:/run/gms.sock;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
diff --git a/deploy/webapp.service.tmpl b/deploy/webapp.service.tmpl
index 35c3dfee..9ca6a661 100644
--- a/deploy/webapp.service.tmpl
+++ b/deploy/webapp.service.tmpl
@@ -1,6 +1,6 @@
[Unit]
Description=Gunicorn for Galaxy Media Site
-Requires=webapp.socket
+Requires=gms.socket
After=network.target
[Service]
@@ -8,10 +8,10 @@ PIDFile=/run/gunicorn/pid
User = ubuntu
Group = www-data
RuntimeDirectory=gunicorn
-WorkingDirectory=/srv/sites/webapp
+WorkingDirectory=/srv/galaxy-media-site/webapp
Environment="PATH={{ PWD }}/.venv/bin:$PATH"
ExecStart={{ PWD }}/.venv/bin/gunicorn --pid /run/gunicorn/pid \
- --bind unix:/run/webapp.sock \
+ --bind unix:/run/gms.sock \
-c {{ PWD }}/gunicorn.py webapp.wsgi
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID
diff --git a/deploy/webapp.socket b/deploy/webapp.socket
index 4eb3bbe1..094d1e5c 100644
--- a/deploy/webapp.socket
+++ b/deploy/webapp.socket
@@ -1,6 +1,6 @@
[Unit]
Description=Galaxy content site socket
[Socket]
-ListenStream=/run/webapp.sock
+ListenStream=/run/gms.sock
[Install]
WantedBy=sockets.target
diff --git a/requirements.txt b/requirements.txt
index 712ae716..0cd61d78 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -20,3 +20,4 @@ lxml
Pillow
requests==2.*
requests_mock==1.*
+sentry-sdk==2.*
diff --git a/webapp/home/forms.py b/webapp/home/forms.py
index d4c1985e..898231f9 100644
--- a/webapp/home/forms.py
+++ b/webapp/home/forms.py
@@ -174,8 +174,8 @@ class QuotaRequestForm(OtherFieldFormMixin, forms.Form):
email = forms.EmailField()
start_date = forms.DateField()
duration_months = forms.IntegerField()
- disk_tb = forms.IntegerField()
- disk_tb_other = forms.IntegerField(required=False)
+ disk_tb = forms.FloatField()
+ disk_tb_other = forms.FloatField(required=False)
description = forms.CharField()
captcha = fields.ReCaptchaField()
accepted_terms = forms.BooleanField()
diff --git a/webapp/home/static/home/css/about.css b/webapp/home/static/home/css/about.css
index 00b62540..64fd5728 100644
--- a/webapp/home/static/home/css/about.css
+++ b/webapp/home/static/home/css/about.css
@@ -11,45 +11,13 @@ hr {
main {
margin-bottom: 10rem;
}
-
-.about-nav {
- display: flex;
- flex-direction: row;
- justify-content: center;
- align-items: center;
- margin-bottom: 3rem;
- padding: 1rem;
- border-bottom: 1px solid #eee;
-}
-.about-nav button {
- display: inline-block;
- color: #aaa;
- font-size: 1rem;
- text-decoration: none;
- margin: .5rem;
- padding: .25rem 1rem;
- min-width: 150px;
- text-align: center;
- background: transparent;
- border: none;
- border-radius: .25rem;
- transition-duration: .25s;
- cursor: pointer;
-}
-.about-nav button.active {
- color: #eee;
- background: var(--color);
- cursor: default;
-}
-.about-nav button:not(.active):hover {
- color: #999;
- background: rgba(50,50,50,0.1);
-}
section {
- display: none;
+ margin-top: 6rem;
+ padding-bottom: 3rem;
+ border-bottom: 1px solid #aaa;
}
-section.show {
- display: block;
+section:last-child {
+ border-bottom: none;
}
.textbox {
margin: 4rem;
@@ -68,25 +36,11 @@ ol.nested ol ol > li {
/* Responsive */
@media (max-width: 1200px) {
- .about-nav {
- padding: 1rem;
- }
- .about-nav button {
- font-size: 0.85rem;
- margin: .25rem;
- padding: .25rem;
- min-width: 125px;
- }
.textbox {
margin: 2rem;
}
}
@media (max-width: 880px) {
- .about-nav button {
- margin: .25rem;
- padding: .25rem;
- min-width: 0px;
- }
.textbox {
margin: 1rem;
}
diff --git a/webapp/home/static/home/css/main.css b/webapp/home/static/home/css/main.css
index fb6955e6..29bc3ac3 100644
--- a/webapp/home/static/home/css/main.css
+++ b/webapp/home/static/home/css/main.css
@@ -137,6 +137,9 @@ section {
margin-left: 0;
margin-right: 0;
}
+.narrow {
+ max-width: 600px;
+}
.container-centered {
/*
For content centered on full
@@ -149,6 +152,10 @@ section {
width: 100%;
height: 85vh;
}
+.my-10 {
+ margin-top: 6rem;
+ margin-bottom: 6rem;
+}
/* Forms */
input.invalid,
diff --git a/webapp/home/static/home/css/request-form.css b/webapp/home/static/home/css/request-form.css
index 459b9014..ace9d5ae 100644
--- a/webapp/home/static/home/css/request-form.css
+++ b/webapp/home/static/home/css/request-form.css
@@ -27,7 +27,7 @@ ul.errorlist {
border: 1px solid var(--error);
border-radius: .5rem;
}
-[class^="col"] {
+.row [class^="col"] {
padding-bottom: 1rem;
}
.blockquote {
diff --git a/webapp/home/static/home/css/requests.css b/webapp/home/static/home/css/requests.css
index c6a5d2c0..1651aa85 100644
--- a/webapp/home/static/home/css/requests.css
+++ b/webapp/home/static/home/css/requests.css
@@ -59,4 +59,17 @@ span.material-icons {
font-size: 0.8rem;
padding: 0;
}
+ .request-menu-cards .ga-btn {
+ min-width: 100px;
+ }
}
+@media (max-width: 575px) {
+ .request-menu-cards .card {
+ padding: 2rem 1rem;
+ margin: .5rem auto;
+ max-width: 300px;
+ }
+ .request-menu-cards .card-body {
+ font-size: 1rem;
+ }
+}
\ No newline at end of file
diff --git a/webapp/home/templates/embed-snippet.html b/webapp/home/templates/embed-snippet.html
index 78707c18..4f719b2b 100644
--- a/webapp/home/templates/embed-snippet.html
+++ b/webapp/home/templates/embed-snippet.html
@@ -10,3 +10,12 @@
{% block content %}
{% include snippet_path %}
{% endblock %}
+
+{% block script %}
+
+{% endblock %}
diff --git a/webapp/home/templates/home/about.html b/webapp/home/templates/home/about.html
index 059f8554..13b99870 100644
--- a/webapp/home/templates/home/about.html
+++ b/webapp/home/templates/home/about.html
@@ -10,35 +10,54 @@
{% block content %}
-
-
- About
-
-
-
- Feature catalogue
-
-
-
- Terms of service
-
-
-
- Data privacy
-
-
-
- Acceptable use
-
-
-
- Service levels
-
-
-
-
+
+ About Galaxy Australia
+
+
+ Galaxy Australia provides researchers with free access to a high-performance computing network through a simple web interface.
+
+
+
+ Galaxy Australia maintains tools, workflows and reference datasets as requested by the Australian research community, making the platform the ideal place for Australian researchers to perform their analyses. If we do not currently support your specific application or species then we will endeavour to make it available.
+ Please just ask!
+
+
+
+ Galaxy Australia is part of the usegalaxy.* initiative. Visit the
+ Galaxy Project Community Hub
+ for more information.
+
+
+
+
+
{% include 'home/snippets/about/about.html' %}
@@ -67,85 +86,8 @@
{% block script %}
-
-
-
{% endblock %}
{% block onload %}
-
-// Prevent default hash scroll
-if (location.hash) {
- console.log("Set timeout to intercept hash scroll");
- setTimeout(function() {
- window.scrollTo(0, 0);
- }, 10);
-}
-
-window.location.hash && setTimeout(function() {
- scrollToId(window.location.hash.slice(1));
-}, 100);
-
-$('a').click( e => {
- if (
- e.target.href.startsWith(window.location.origin)
- && e.target.href.includes('#')) {
- // It's an internal link
- e.preventDefault();
- scrollToId(e.target.href.split('#')[1]);
- }
-})
-
{% endblock %}
diff --git a/webapp/home/templates/home/header-export.html b/webapp/home/templates/home/header-export.html
index cc49fd95..f4730bd4 100644
--- a/webapp/home/templates/home/header-export.html
+++ b/webapp/home/templates/home/header-export.html
@@ -22,7 +22,7 @@
-
+
{% block content %}
{% endblock %}
diff --git a/webapp/home/templates/home/header.html b/webapp/home/templates/home/header.html
index eaf720fc..81def67e 100644
--- a/webapp/home/templates/home/header.html
+++ b/webapp/home/templates/home/header.html
@@ -200,18 +200,28 @@
// Remove links to usegalaxy.org.au if in iframe
// ...otherwise risk having galaxy-in-galaxy which is very weird!
+ // If GMS (local) URL then do nothing
+ // If parent root URL then remove href
+ // Else must be:
+ // - non-root parent URL
+ // - OR external URL
+ // -> set target="_blank" (opens in new tab)
+ const urlParams = new URLSearchParams(window.location.search);
+ const parentHostname = urlParams.get('hostname') || 'usegalaxy.org.au';
if ( inIframe() ) {
$('a').each( (i, el) => {
if (
el.href
- && el.href.includes('https://{{ HOSTNAME }}')
+ && !el.href.startsWith('https://{{ HOSTNAME }}')
&& !isLabPage()
) {
- if (el.href.replace(/\/$/, "") === 'https://{{ HOSTNAME }}') {
- console.log(`Remove href from anchor: ${el.href}`);
+ if (el.href.replace(/\/$/, "") === `https://${parentHostname}`) {
+ // It's a link to the parent site root URL
+ // console.log(`Remove href from anchor: ${el.href}`);
$(el).removeAttr("href");
} else {
- console.log(`Set target="_blank" on anchor: ${el.href}`);
+ // It's a link to the parent site with a path, or an external site
+ // console.log(`Set target="_blank" on anchor: ${el.href}`);
$(el).attr("target", "_blank");
}
}
diff --git a/webapp/home/templates/home/requests/access/index.html b/webapp/home/templates/home/requests/access/index.html
index 113a7f1c..7fcc2889 100644
--- a/webapp/home/templates/home/requests/access/index.html
+++ b/webapp/home/templates/home/requests/access/index.html
@@ -81,6 +81,20 @@ Request access to specialist tools
+
+
+
+
+ Analyse data-independent acquisition (DIA) proteomics data with DiaNN
+
+
+
+
+
diff --git a/webapp/home/templates/home/requests/access/snippets/agree-terms-modal.html b/webapp/home/templates/home/requests/access/snippets/agree-terms-modal.html
index 9439aad1..7435d57b 100644
--- a/webapp/home/templates/home/requests/access/snippets/agree-terms-modal.html
+++ b/webapp/home/templates/home/requests/access/snippets/agree-terms-modal.html
@@ -76,6 +76,8 @@
.css('padding', '1rem'));
{% endif %}
+ const isMac = () => navigator.platform.toUpperCase().indexOf('MAC') >= 0;
+
function agreeTermsAction(el) {
enableTermsInput();
$('#agreeTermsInput').attr('checked', true);
@@ -92,16 +94,20 @@
tooltip.disable();
}
+
function setEventHandler() {
const termsContainer = $('#termsModal iframe').contents().find('body');
if (!termsContainer.length) {
return setTimeout(setEventHandler, 100);
}
+ if (isMac()) {
+ return enableAgreeTermsButton();
+ }
$('#termsModal iframe').contents().on('scroll', (event) => {
const scrollFromEnd = $(termsContainer)[0].scrollHeight
- $('#termsModal iframe').contents().scrollTop()
- $('#termsModal iframe').height();
- if (scrollFromEnd < 50) enableAgreeTermsButton();
+ scrollFromEnd < 50 && enableAgreeTermsButton();
});
termsContainer.css('margin', 'auto');
}
diff --git a/webapp/home/templates/home/requests/menu.html b/webapp/home/templates/home/requests/menu.html
index 708ed181..6a65700a 100644
--- a/webapp/home/templates/home/requests/menu.html
+++ b/webapp/home/templates/home/requests/menu.html
@@ -70,7 +70,8 @@ save
key
- Request access to specialised tools AlphaFold 2, FGENESH++ and Cell Ranger
+ Request access to specialised tools AlphaFold 2, FGENESH++,
+ Cell Ranger and more...
diff --git a/webapp/home/templates/home/requests/quota.html b/webapp/home/templates/home/requests/quota.html
index 78ccb13a..9e6217b3 100644
--- a/webapp/home/templates/home/requests/quota.html
+++ b/webapp/home/templates/home/requests/quota.html
@@ -40,15 +40,15 @@ Galaxy Australia Quota Increase Application
{% csrf_token %}
-
-
+
+
Full name
{{ form.name.errors }}
-
-
-
+
+
When do you plan to start your data analysis?
@@ -87,28 +87,36 @@
Galaxy Australia Quota Increase Application
{{ form.start_date.errors }}
-
+
For how long will you need your extended data quota?
-
+
+
+ 6 months
+
+
+
+ 12 months
+
{{ form.duration_months.errors }}
-
- Justification and comments
+ Justification for quota increase
{{ form.description.errors }}
- Please briefly justify your need for additional data storage.
- Describe your data, file types and why they are required for your research.
+ Please briefly justify your need for additional data storage by
+ describing your data and intended analysis.
-
+
Agreement on the use of the Galaxy Australia Server
diff --git a/webapp/home/templates/home/snippets/about/about.html b/webapp/home/templates/home/snippets/about/about.html
index a849553c..36e2fd27 100644
--- a/webapp/home/templates/home/snippets/about/about.html
+++ b/webapp/home/templates/home/snippets/about/about.html
@@ -1,24 +1,7 @@
{% load static %}
-
About Galaxy Australia
-
-
- Galaxy Australia provides researchers with free access to a high-performance computing network through a simple web interface.
-
-
-
- Galaxy Australia maintains tools, workflows and reference datasets as requested by the Australian research community, making the platform the ideal place for Australian researchers to perform their analyses. If we do not currently support your specific application or species then we will endeavour to make it available.
- Please just ask!
-
-
-
- Galaxy Australia is part of the usegalaxy.* initiative. Visit the
- Galaxy Project Community Hub
- for more information.
-
-
Galaxy Australia Acknowledgment Statement
@@ -40,107 +23,111 @@
-
-
- Operational Partners
-
-
-Australian BioCommons (hosted by
- the University of Melbourne )
- operates Galaxy Australia in collaboration with
- QCIF ,
- The University of Melbourne
- and
- AARNet .
- This service forms part of the national Australian BioCommons infrastructure.
-
-
-
-
-
diff --git a/webapp/home/tests.py b/webapp/home/tests.py
index ffd85e45..1143147d 100644
--- a/webapp/home/tests.py
+++ b/webapp/home/tests.py
@@ -21,6 +21,20 @@
from webapp.test import TestCase
TEST_DATA_DIR = Path(__file__).parent / 'test/data'
+
+# Endpoints to test for HTTP 200
+TEST_ENDPOINTS = [
+ '/about',
+ '/request',
+ '/request/tool',
+ '/request/quota',
+ '/request/support',
+ '/request/access',
+ '/list-of-institutions.html',
+]
+
+
+# Galaxy Labs
TEST_LAB_NAME = 'Antarctica'
TEST_LAB_LAB_NAME = 'Galaxy Lab Pages'.upper()
TEST_LAB_NATIONALITY = 'Antarctican'
@@ -172,6 +186,11 @@ def test_aaf_webpage(self):
'University of Queensland'
)
+ def test_webpages(self):
+ for endpoint in TEST_ENDPOINTS:
+ response = self.client.get(endpoint)
+ self.assertLess(response.status_code, 300)
+
def test_utility_institution(self):
assert institution.is_institution_email('johndoe@uq.edu.au')
assert not institution.is_institution_email('johndoe@gmail.com')
diff --git a/webapp/home/views.py b/webapp/home/views.py
index d8589394..5d94f673 100644
--- a/webapp/home/views.py
+++ b/webapp/home/views.py
@@ -313,13 +313,28 @@ def custom_400(request, exception, template_name="400.html"):
def embed_snippet(request, snippet_path):
"""Serve an embeddable snippet."""
+ ALLOW_STYLE_PARAMS = ['overflow']
+ body_style_data = {
+ k: request.GET.get(k)
+ for k in ALLOW_STYLE_PARAMS
+ if k in request.GET
+ }
+ body_style = ' '.join(
+ f'{k}: {v};'
+ for k, v in body_style_data.items()
+ )
try:
if 'snippets' not in snippet_path:
raise Http404
return render(request, 'embed-snippet.html', {
'title': 'Galaxy Media - embedded snippet',
'snippet_path': snippet_path,
- 'crop_margin': True, # could make this configurable in future
+ # Can be referenced in snippet templates:
+ 'crop_margin': request.GET.get(
+ 'crop',
+ 'true',
+ ).lower() in ('true', '1', 'yes'),
+ 'body_style': body_style,
})
except TemplateDoesNotExist:
raise Http404
diff --git a/webapp/utils/slack.py b/webapp/utils/slack.py
index a4145816..1cba9c19 100644
--- a/webapp/utils/slack.py
+++ b/webapp/utils/slack.py
@@ -11,11 +11,15 @@ def post(message):
key = os.environ.get("SLACK_API_KEY")
user_id = os.environ.get("SLACK_MENTION_USER_ID")
channel_id = os.environ.get("SLACK_CHANNEL_ID")
+ message = ""
if key is None:
return
if user_id:
- message = f'<@{user_id}> {message}'
+ message += f'<@{user_id}>'
+
+ message += f' [hostname: {os.getenv("HOSTNAME")}]'
+ message += f' {message}'
requests.post(
SLACK_URL,
diff --git a/webapp/webapp/settings/base.py b/webapp/webapp/settings/base.py
index 5e62519c..eff8ca4b 100644
--- a/webapp/webapp/settings/base.py
+++ b/webapp/webapp/settings/base.py
@@ -133,7 +133,7 @@
EMAIL_FROM_ADDRESS = os.environ['MAIL_FROM_ADDRESS']
EMAIL_TO_ADDRESS = os.environ['MAIL_TO_ADDRESS']
-SERVER_EMAIL = os.environ['MAIL_FROM_ADDRESS']
+SERVER_EMAIL = os.getenv('SERVER_EMAIL', EMAIL_FROM_ADDRESS)
EMAIL_SUBJECT_PREFIX = os.getenv('EMAIL_SUBJECT_PREFIX', 'GMS: ')
if os.getenv('MAIL_HOSTNAME'):
diff --git a/webapp/webapp/settings/log/config.py b/webapp/webapp/settings/log/config.py
index 165d6683..981450bf 100644
--- a/webapp/webapp/settings/log/config.py
+++ b/webapp/webapp/settings/log/config.py
@@ -114,7 +114,7 @@ def configure_logging(LOG_ROOT):
'debug_file',
'main_file',
'error_file',
- 'error_mail',
+ # 'error_mail',
'error_slack',
'console'
],
diff --git a/webapp/webapp/settings/prod.py b/webapp/webapp/settings/prod.py
index a0eecac8..a888310d 100644
--- a/webapp/webapp/settings/prod.py
+++ b/webapp/webapp/settings/prod.py
@@ -1,6 +1,10 @@
+# flake8: noqa
+
"""Settings for production."""
import os
+import logging
+import sentry_sdk
from .base import *
from . import validate
@@ -60,4 +64,14 @@
LOGGING = config.configure_logging(LOG_ROOT)
# Use manifest to manage static file versions for cache busting:
-STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'
+STATICFILES_STORAGE = (
+ 'django.contrib.staticfiles.storage'
+ '.ManifestStaticFilesStorage')
+
+sentry_sdk.init(
+ dsn="https://426e64399bbafe4210c4fa647c7a2f5b@sentry.galaxyproject.org/20",
+ # Set traces_sample_rate to 1.0 to capture 100%
+ # of transactions for tracing.
+ traces_sample_rate=1.0,
+)
+logging.getLogger('sentry_sdk').setLevel(logging.ERROR)