various interface changes
This commit is contained in:
parent
7307ec3931
commit
2445fadf63
11
README.md
11
README.md
|
@ -5,15 +5,18 @@ A django app running on Docker. Replaces _Aus GLAM Blogs_.
|
||||||
## Deploy
|
## Deploy
|
||||||
|
|
||||||
* `docker compose build`
|
* `docker compose build`
|
||||||
* `./glamr-dev createsuperuser`
|
* `./glamr-dev makemigrations` (may get a DB connection error here, ignore it or run again)
|
||||||
* `./glamr-dev makemigrations`
|
|
||||||
* `./glamr-dev migrate`
|
* `./glamr-dev migrate`
|
||||||
|
* `./glamr-dev createsuperuser`
|
||||||
* `docker compose up`
|
* `docker compose up`
|
||||||
|
|
||||||
* set up database backups (as cron jobs):
|
* set up database backups (as cron jobs):
|
||||||
|
|
||||||
* `/usr/bin/docker exec -u root ausglamr-db-1 pg_dump -v -Fc -U ausglamr -d "ausglamr" -f /tmp/ausglamr_backup.dump`
|
* `./glamr-dev backup`
|
||||||
* `/usr/bin/docker cp ausglamr-db-1:/tmp/ausglamr_backup.dump /home/hugh/backups/`
|
|
||||||
|
* `/snap/bin/docker exec -u root ausglamr_db_1 pg_dump -v -Fc -U ausglamr -d "ausglamr" -f /tmp/ausglamr_backup.dump`
|
||||||
|
* `/snap/bin/docker cp ausglamr_db_1:/tmp/ausglamr_backup.dump /home/hugh/backups/`
|
||||||
|
* `mv /home/hugh/backups/ausglamr_backup.dump /home/hugh/backups/ausglamr_backup_$(date +'%a').dump`
|
||||||
|
|
||||||
* set up cron jobs for management commands as below
|
* set up cron jobs for management commands as below
|
||||||
|
|
||||||
|
|
|
@ -32,11 +32,11 @@ SECRET_KEY = env("SECRET_KEY")
|
||||||
|
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = env("DEBUG")
|
DEBUG = env("DEBUG")
|
||||||
ALLOWED_HOSTS = [env("DOMAIN")]
|
ALLOWED_HOSTS = ['.localhost', '127.0.0.1', '[::1]', env("DOMAIN")]
|
||||||
CSRF_COOKIE_SECURE=True
|
CSRF_COOKIE_SECURE = True
|
||||||
SESSION_COOKIE_SECURE=True
|
SESSION_COOKIE_SECURE = True
|
||||||
CSRF_TRUSTED_ORIGINS = [f'https://{env("DOMAIN")}']
|
CSRF_TRUSTED_ORIGINS = [f'https://{env("DOMAIN")}']
|
||||||
CONN_MAX_AGE=None # persistent DB connection
|
CONN_MAX_AGE = None # persistent DB connection
|
||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
|
|
||||||
|
|
|
@ -15,10 +15,14 @@ urlpatterns = [
|
||||||
path("contribute", views.Contribute.as_view(), name="contribute"),
|
path("contribute", views.Contribute.as_view(), name="contribute"),
|
||||||
path("contact", views.Contact.as_view(), name="contact"),
|
path("contact", views.Contact.as_view(), name="contact"),
|
||||||
path("blogs", views.Blogs.as_view(), name="blogs"),
|
path("blogs", views.Blogs.as_view(), name="blogs"),
|
||||||
|
path("blogs/<category>", views.Blogs.as_view(), name="blog-category "),
|
||||||
path("events", views.Conferences.as_view(), name="events"),
|
path("events", views.Conferences.as_view(), name="events"),
|
||||||
path("cfps", views.CallsForPapers.as_view(), name="cfps"),
|
path("events/<category>", views.Conferences.as_view(), name="events-category"),
|
||||||
|
re_path(r"^cfps/?$", views.CallsForPapers.as_view(), name="cfps"),
|
||||||
path("groups", views.Groups.as_view(), name="groups"),
|
path("groups", views.Groups.as_view(), name="groups"),
|
||||||
|
path("groups/<category>", views.Groups.as_view(), name="group-category"),
|
||||||
path("newsletters", views.Newsletters.as_view(), name="newsletters"),
|
path("newsletters", views.Newsletters.as_view(), name="newsletters"),
|
||||||
|
path("newsletters/<category>", views.Newsletters.as_view(), name="newsletters-category"),
|
||||||
path("register-blog", views.RegisterBlog.as_view(), name="register-blog"),
|
path("register-blog", views.RegisterBlog.as_view(), name="register-blog"),
|
||||||
path(
|
path(
|
||||||
"submit-blog-registration",
|
"submit-blog-registration",
|
||||||
|
|
|
@ -20,9 +20,7 @@ def approve(modeladmin, request, queryset):
|
||||||
|
|
||||||
if hasattr(instance, "event"): # CFP
|
if hasattr(instance, "event"): # CFP
|
||||||
recipient = instance.event.contact_email
|
recipient = instance.event.contact_email
|
||||||
if hasattr(
|
if hasattr(instance, "contact_email"):
|
||||||
instance, "contact_email"
|
|
||||||
): # overrides above in case needed in future
|
|
||||||
recipient = instance.contact_email
|
recipient = instance.contact_email
|
||||||
|
|
||||||
if recipient:
|
if recipient:
|
||||||
|
@ -32,7 +30,10 @@ def approve(modeladmin, request, queryset):
|
||||||
title = instance.title
|
title = instance.title
|
||||||
|
|
||||||
subject = f"✅ {title} has been approved on AusGLAMR!"
|
subject = f"✅ {title} has been approved on AusGLAMR!"
|
||||||
message = f"<html><body><p>{title} has been approved on <a href='https://{settings.DOMAIN}'>AusGLAMR</a>. Hooray!</p></body></html>"
|
message = f"<html><body><p>{title} has been approved on <a href='https://{settings.DOMAIN}'>AusGLAMR</a>. Hooray!</p>"
|
||||||
|
if type(instance).__name__ == "Event":
|
||||||
|
message += f"<p>You can now optionally <a href='https://{settings.DOMAIN}/register-cfp'>register a call for papers</a>.</p>"
|
||||||
|
message += "</body></html>"
|
||||||
|
|
||||||
utilities.send_email(subject, message, recipient)
|
utilities.send_email(subject, message, recipient)
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,9 @@ class Command(BaseCommand):
|
||||||
)
|
)
|
||||||
|
|
||||||
cutoff = timezone.now() - timedelta(days=7)
|
cutoff = timezone.now() - timedelta(days=7)
|
||||||
blogs = models.Blog.objects.filter(approved=True, updateddate__gte=cutoff)
|
blogs = models.Blog.objects.filter(
|
||||||
|
approved=True, active=True, added__gte=cutoff
|
||||||
|
)
|
||||||
articles = models.Article.objects.filter(pubdate__gte=cutoff)
|
articles = models.Article.objects.filter(pubdate__gte=cutoff)
|
||||||
events = models.Event.objects.filter(approved=True, pub_date__gte=cutoff)
|
events = models.Event.objects.filter(approved=True, pub_date__gte=cutoff)
|
||||||
cfps = models.CallForPapers.objects.filter(
|
cfps = models.CallForPapers.objects.filter(
|
||||||
|
|
|
@ -25,7 +25,7 @@ class BlogData(models.Model):
|
||||||
"""Base bloggy data"""
|
"""Base bloggy data"""
|
||||||
|
|
||||||
title = models.CharField(max_length=2000)
|
title = models.CharField(max_length=2000)
|
||||||
author_name = models.CharField(max_length=1000, null=True)
|
author_name = models.CharField(max_length=1000, null=True, blank=True)
|
||||||
url = models.URLField(max_length=2000, unique=True)
|
url = models.URLField(max_length=2000, unique=True)
|
||||||
description = models.TextField(null=True, blank=True)
|
description = models.TextField(null=True, blank=True)
|
||||||
updateddate = models.DateTimeField()
|
updateddate = models.DateTimeField()
|
||||||
|
@ -55,6 +55,7 @@ class Blog(BlogData):
|
||||||
|
|
||||||
feed = models.URLField(max_length=2000)
|
feed = models.URLField(max_length=2000)
|
||||||
category = models.CharField(choices=Category.choices, max_length=4)
|
category = models.CharField(choices=Category.choices, max_length=4)
|
||||||
|
added = models.DateTimeField()
|
||||||
approved = models.BooleanField(default=False)
|
approved = models.BooleanField(default=False)
|
||||||
announced = models.BooleanField(default=False)
|
announced = models.BooleanField(default=False)
|
||||||
failing = models.BooleanField(default=False, blank=True, null=True)
|
failing = models.BooleanField(default=False, blank=True, null=True)
|
||||||
|
@ -66,6 +67,11 @@ class Blog(BlogData):
|
||||||
)
|
)
|
||||||
contact_email = models.EmailField(blank=True, null=True)
|
contact_email = models.EmailField(blank=True, null=True)
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
if not self.added:
|
||||||
|
self.added = timezone.now()
|
||||||
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
def announce(self):
|
def announce(self):
|
||||||
"""queue announcement"""
|
"""queue announcement"""
|
||||||
|
|
||||||
|
@ -108,7 +114,7 @@ class Article(BlogData):
|
||||||
blog = models.ForeignKey(Blog, on_delete=models.CASCADE, related_name="articles")
|
blog = models.ForeignKey(Blog, on_delete=models.CASCADE, related_name="articles")
|
||||||
pubdate = models.DateTimeField()
|
pubdate = models.DateTimeField()
|
||||||
guid = models.CharField(max_length=2000)
|
guid = models.CharField(max_length=2000)
|
||||||
tags = models.ManyToManyField("Tag", related_name="articles")
|
tags = models.ManyToManyField("Tag", related_name="articles", null=True, blank=True)
|
||||||
|
|
||||||
# pylint: disable=undefined-variable
|
# pylint: disable=undefined-variable
|
||||||
def announce(self):
|
def announce(self):
|
||||||
|
|
|
@ -9,10 +9,10 @@ from .utils import Announcement, Category
|
||||||
class Event(models.Model):
|
class Event(models.Model):
|
||||||
"""a event"""
|
"""a event"""
|
||||||
|
|
||||||
name = models.CharField(max_length=999)
|
name = models.CharField(max_length=100)
|
||||||
category = models.CharField(choices=Category.choices, max_length=4)
|
category = models.CharField(choices=Category.choices, max_length=4)
|
||||||
url = models.URLField(max_length=400, unique=True)
|
url = models.URLField(max_length=400, unique=True)
|
||||||
description = models.TextField(null=True, blank=True)
|
description = models.TextField(null=True, blank=True, max_length=250)
|
||||||
pub_date = models.DateTimeField() # for RSS feed
|
pub_date = models.DateTimeField() # for RSS feed
|
||||||
start_date = models.DateField()
|
start_date = models.DateField()
|
||||||
announcements = models.IntegerField(null=True, blank=True, default=0)
|
announcements = models.IntegerField(null=True, blank=True, default=0)
|
||||||
|
@ -55,9 +55,9 @@ class CallForPapers(models.Model):
|
||||||
"""a event call for papers/presentations"""
|
"""a event call for papers/presentations"""
|
||||||
|
|
||||||
name = models.CharField(
|
name = models.CharField(
|
||||||
max_length=999
|
max_length=100
|
||||||
) # "Call for papers", "call for participation" etc
|
) # "Call for papers", "call for participation" etc
|
||||||
details = models.TextField(null=True, blank=True)
|
details = models.TextField(null=True, blank=True, max_length=250)
|
||||||
pub_date = models.DateTimeField(null=True, default=None)
|
pub_date = models.DateTimeField(null=True, default=None)
|
||||||
opening_date = models.DateField()
|
opening_date = models.DateField()
|
||||||
closing_date = models.DateField()
|
closing_date = models.DateField()
|
||||||
|
|
|
@ -9,12 +9,12 @@ from .utils import Announcement, Category, GroupType
|
||||||
class Group(models.Model):
|
class Group(models.Model):
|
||||||
"""a group on email, discord, slack etc"""
|
"""a group on email, discord, slack etc"""
|
||||||
|
|
||||||
name = models.CharField(max_length=999)
|
name = models.CharField(max_length=100)
|
||||||
category = models.CharField(choices=Category.choices, max_length=4)
|
category = models.CharField(choices=Category.choices, max_length=4)
|
||||||
type = models.CharField(choices=GroupType.choices, max_length=4)
|
type = models.CharField(choices=GroupType.choices, max_length=4)
|
||||||
url = models.URLField(max_length=400, unique=True)
|
url = models.URLField(max_length=400, unique=True)
|
||||||
registration_url = models.URLField(max_length=400, unique=True)
|
registration_url = models.URLField(max_length=400, unique=True)
|
||||||
description = models.TextField(null=True, blank=True)
|
description = models.TextField(null=True, blank=True, max_length=250)
|
||||||
contact_email = models.EmailField(blank=True, null=True)
|
contact_email = models.EmailField(blank=True, null=True)
|
||||||
announced = models.BooleanField(default=False)
|
announced = models.BooleanField(default=False)
|
||||||
approved = models.BooleanField(default=False)
|
approved = models.BooleanField(default=False)
|
||||||
|
|
|
@ -9,12 +9,12 @@ from .utils import Announcement, Category
|
||||||
class Newsletter(models.Model):
|
class Newsletter(models.Model):
|
||||||
"""a newsletter"""
|
"""a newsletter"""
|
||||||
|
|
||||||
name = models.CharField(max_length=999)
|
name = models.CharField(max_length=100)
|
||||||
author = models.CharField(max_length=999)
|
author = models.CharField(max_length=100)
|
||||||
category = models.CharField(choices=Category.choices, max_length=4)
|
category = models.CharField(choices=Category.choices, max_length=4)
|
||||||
url = models.URLField(max_length=400, unique=True)
|
url = models.URLField(max_length=400, unique=True)
|
||||||
|
|
||||||
description = models.TextField(null=True, blank=True)
|
description = models.TextField(null=True, blank=True, max_length=250)
|
||||||
activitypub_account_name = models.CharField(max_length=200, blank=True, null=True)
|
activitypub_account_name = models.CharField(max_length=200, blank=True, null=True)
|
||||||
contact_email = models.EmailField(blank=True, null=True)
|
contact_email = models.EmailField(blank=True, null=True)
|
||||||
announced = models.BooleanField(default=False)
|
announced = models.BooleanField(default=False)
|
||||||
|
|
|
@ -1,20 +1,28 @@
|
||||||
{% extends "layout.html" %}
|
{% extends "layout.html" %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="listing l-three header">
|
<div>
|
||||||
|
<a href="{% url 'register-blog' %}"><button class="button button-first">Add a Blog</button></a>
|
||||||
|
</div>
|
||||||
|
<div class="listing l-three header">
|
||||||
<div>Title</div>
|
<div>Title</div>
|
||||||
<div>Category</div>
|
<div>Category</div>
|
||||||
<div>Last updated</div>
|
<div>Last updated</div>
|
||||||
|
</div>
|
||||||
|
<hr/>
|
||||||
|
{% for blog in blogs %}
|
||||||
|
<div class="listing l-three">
|
||||||
|
<div>
|
||||||
|
<p><a href="{{blog.url}}">{{blog.title}}</a></p>
|
||||||
|
<p>{{blog.description}}</p>
|
||||||
</div>
|
</div>
|
||||||
<hr/>
|
<div><div class="end badge badge_{{blog.category}}"><a href="/blogs/{{blog.category}}">{{blog.category_name}}</a></div></div>
|
||||||
{% for blog in blogs %}
|
|
||||||
<div class="listing l-three">
|
|
||||||
<div><a href="{{blog.url}}">{{blog.title}}</a><p>{{blog.description}}</p></div>
|
|
||||||
<div><div class="end badge badge_{{blog.category}}">{{blog.category_name}}</div></div>
|
|
||||||
<div>{{ blog.updateddate|date:"D d M Y" }}
|
<div>{{ blog.updateddate|date:"D d M Y" }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<hr/>
|
<hr/>
|
||||||
{% endfor %}
|
{% empty %}
|
||||||
|
<p>Oh no! There are no blogs currently registered. Try checking out <a href="{% url 'newsletters' %}">some newsletters</a>.</p>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
|
@ -10,7 +10,7 @@
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
{% for cfp in cfps %}
|
{% for cfp in cfps %}
|
||||||
<div class="listing l-three">
|
<div class="listing l-three" id="cfp_{{cfp.id}}">
|
||||||
<div>
|
<div>
|
||||||
<p><strong>{{cfp.name}}</strong></p>
|
<p><strong>{{cfp.name}}</strong></p>
|
||||||
<p>{{cfp.details}}</p>
|
<p>{{cfp.details}}</p>
|
||||||
|
@ -19,6 +19,8 @@
|
||||||
<span class="closing-date">{{cfp.closing_date}}</span>
|
<span class="closing-date">{{cfp.closing_date}}</span>
|
||||||
</div>
|
</div>
|
||||||
<hr/>
|
<hr/>
|
||||||
|
{% empty %}
|
||||||
|
<p>Oh no! There are no Calls for Papers currently open. Try checking out <a href="{% url 'newsletters' %}">some newsletters</a>.</p>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,30 +2,33 @@
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class="listing l-four header">
|
<div>
|
||||||
<span>Name</span>
|
<a href="{% url 'register-event' %}"><button class="button button-first">Add an Event</button></a>
|
||||||
|
<a href="{% url 'register-cfp' %}"><button class="button">Add a CFP</button></a>
|
||||||
|
</div>
|
||||||
|
<div class="listing l-three header">
|
||||||
|
<span>Description</span>
|
||||||
<span>Category</span>
|
<span>Category</span>
|
||||||
<span>Start Date</span>
|
<span>Start Date</span>
|
||||||
<span>Description</span>
|
</div>
|
||||||
</div>
|
<hr/>
|
||||||
<hr/>
|
{% for con in cons %}
|
||||||
|
<div class="listing l-three">
|
||||||
|
|
||||||
{% for con in cons %}
|
|
||||||
<div>{{con.call_for_papers.closing_date}}</div>
|
|
||||||
<div class="listing l-four">
|
|
||||||
<span><a href="{{con.url}}">{{con.name}}</a></span>
|
|
||||||
<span><span class="badge badge_{{con.category}}">{{con.category_name}}</span></span>
|
|
||||||
<span class="start-date">{{con.start_date}}</span>
|
|
||||||
<div>
|
<div>
|
||||||
<div>{{con.description}}</div>
|
<p><a href="{{con.url}}">{{con.name}}</a></p>
|
||||||
|
<div>
|
||||||
|
<p>{{con.description}}</p>
|
||||||
{% if con.call_for_papers %}
|
{% if con.call_for_papers %}
|
||||||
<div><em><a href="{% url 'cfps' %}">{{ con.call_for_papers }}</a></em></div>
|
<p><em><a href="/cfps/#cfp_{{con.call_for_papers.id}}">{{con.call_for_papers.name}} closes {{ con.call_for_papers.closing_date|date:"D d M" }}</a></em></p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<hr/>
|
<span><span class="badge badge_{{con.category}}"><a href="/events/{{con.category}}">{{con.category_name}}</a></span></span>
|
||||||
{% endfor %}
|
<span class="start-date">{{con.start_date}}</span>
|
||||||
|
</div>
|
||||||
|
<hr/>
|
||||||
|
{% empty %}
|
||||||
|
<p>Oh no! There are no events currently registered. Try checking out <a href="{% url 'blogs' %}">some blogs</a>.</p>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
|
@ -1,20 +1,26 @@
|
||||||
{% extends "layout.html" %}
|
{% extends "layout.html" %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="listing l-four header">
|
<div>
|
||||||
<span>Name</span>
|
<a href="{% url 'register-group' %}"><button class="button button-first">Add a Group</button></a>
|
||||||
<span>Category</span>
|
</div>
|
||||||
|
<div class="listing l-three header">
|
||||||
<span>Description</span>
|
<span>Description</span>
|
||||||
|
<span>Category</span>
|
||||||
<span>Registration Link</span>
|
<span>Registration Link</span>
|
||||||
</div>
|
</div>
|
||||||
<hr/>
|
<hr/>
|
||||||
{% for group in groups %}
|
{% for group in groups %}
|
||||||
<div class="listing l-four">
|
<div class="listing l-three">
|
||||||
<span><a href="{{group.url}}">{{group.name}}</a></span>
|
<span>
|
||||||
<span><span class="badge badge_{{group.category}}">{{group.category_name}}</span></span>
|
<p><a href="{{group.url}}">{{group.name}}</a></p>
|
||||||
<span>{{group.description}}</span>
|
<p><span>{{group.description}}</span></p>
|
||||||
|
</span>
|
||||||
|
<span><span class="badge badge_{{group.category}}"><a href="/groups/{{group.category}}">{{group.category_name}}</a></span></span>
|
||||||
<span><a href="{{group.registration_url}}">Join the {{group.reg_type}}</a></span>
|
<span><a href="{{group.registration_url}}">Join the {{group.reg_type}}</a></span>
|
||||||
</div>
|
</div>
|
||||||
<hr/>
|
<hr/>
|
||||||
|
{% empty %}
|
||||||
|
<p>Oh no! There are no groups currently registered. Try checking out <a href="{% url 'newsletters' %}">some newsletters</a>.</p>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endblock %}
|
{% endblock %}
|
|
@ -1,6 +1,9 @@
|
||||||
{% extends "layout.html" %}
|
{% extends "layout.html" %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
<div>
|
||||||
|
<a href="{% url 'register-newsletter' %}"><button class="button button-first">Add a Newsletter</button></a>
|
||||||
|
</div>
|
||||||
<div class="listing l-three header">
|
<div class="listing l-three header">
|
||||||
<span>Title</span>
|
<span>Title</span>
|
||||||
<span>Author</span>
|
<span>Author</span>
|
||||||
|
@ -11,8 +14,10 @@
|
||||||
<div class="listing l-three">
|
<div class="listing l-three">
|
||||||
<span><a href="{{pub.url}}">{{pub.name}}</a></span>
|
<span><a href="{{pub.url}}">{{pub.name}}</a></span>
|
||||||
<span>{{pub.author}}</span>
|
<span>{{pub.author}}</span>
|
||||||
<span><span class="badge badge_{{pub.category}}">{{pub.category_name}}</span></span>
|
<span><span class="badge badge_{{pub.category}}"><a href="/newsletters/{{pub.category}}">{{pub.category_name}}</a></span></span>
|
||||||
</div>
|
</div>
|
||||||
<hr/>
|
<hr/>
|
||||||
|
{% empty %}
|
||||||
|
<p>Oh no! There are no newsletter currently registered. Try checking out <a href="{% url 'blogs' %}">some blogs</a>.</p>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endblock %}
|
{% endblock %}
|
|
@ -27,36 +27,7 @@
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="columns eight">
|
<div class="columns eight">
|
||||||
{% if conf_name %}
|
{{ form }}
|
||||||
<input hidden type="text" name="event" value="{{ form.event.value }}">
|
|
||||||
{% else %}
|
|
||||||
<label for="{{ form.event.id_for_label }}">Event:</label>
|
|
||||||
{% if errors %} {{ form.event.errors }} {% endif %}
|
|
||||||
{{ form.event }}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<label for="{{ form.name.id_for_label }}">Name:</label>
|
|
||||||
{% if errors %} {{ form.name.errors }} {% endif %}
|
|
||||||
<p class="hint">e.g. "Call for Papers", "Request for submissions" etc</p>
|
|
||||||
<input type="text" name="name" id="name" class="u-full-width" required="">
|
|
||||||
{% if errors %} {{ form.details.errors }} {% endif %}
|
|
||||||
<label for="{{ form.details.id_for_label }}">Details:</label>
|
|
||||||
<textarea name="details" id="details" class="u-full-width"></textarea>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<span class="columns four">
|
|
||||||
{% if errors %} {{ form.opening_date.errors }} {% endif %}
|
|
||||||
<label for="{{ form.opening_date.id_for_label }}">opening_date:</label>
|
|
||||||
{% if errors %} {{ form.opening_date.errors }} {% endif %}
|
|
||||||
{{ form.opening_date }}
|
|
||||||
</span>
|
|
||||||
<span class="columns four">
|
|
||||||
<label for="{{ form.closing_date.id_for_label }}">closing_date:</label>
|
|
||||||
{% if errors %} {{ form.closing_date.errors }} {% endif %}
|
|
||||||
{{ form.closing_date }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<input class="button-primary u-pull-right" type="submit" value="Register!">
|
<input class="button-primary u-pull-right" type="submit" value="Register!">
|
||||||
<a href="/"><button class="button u-pull-right button-first" type="button">No thanks</button></a>
|
<a href="/"><button class="button u-pull-right button-first" type="button">No thanks</button></a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>{{ title }}</title>
|
<title>{{ title }}</title>
|
||||||
|
<link rel="icon" type="image/svg" href="{% static 'favicon.svg' %}" />
|
||||||
<link rel="stylesheet" href="{% static 'css/normalize.css' %}" type="text/css" />
|
<link rel="stylesheet" href="{% static 'css/normalize.css' %}" type="text/css" />
|
||||||
<link rel="stylesheet" href="{% static 'css/skeleton.css' %}" type="text/css" />
|
<link rel="stylesheet" href="{% static 'css/skeleton.css' %}" type="text/css" />
|
||||||
<link rel="stylesheet" href="{% static 'css/custom.css' %}" type="text/css" />
|
<link rel="stylesheet" href="{% static 'css/custom.css' %}" type="text/css" />
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
|
|
||||||
{% if register_type == "email address" %}
|
{% if register_type == "email address" %}
|
||||||
<p>Check your inbox to confirm your subscription. You can opt-out at any time by clicking the link at the bottom of the weekly emails.</p>
|
<p>Check your inbox to confirm your subscription. You can opt-out at any time by clicking the link at the bottom of the weekly emails.</p>
|
||||||
|
{% elif register_type == "conference" %}
|
||||||
|
<p>Once your conference is approved, you will be able to register a <a href="{% url 'cfps' %}">Call for Papers</a> if you would like to do so.</p>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p>Your {{ register_type }} registration will be reviewed before being added to <em>Aus GLAMR</em>.</p>
|
<p>Your {{ register_type }} registration will be reviewed before being added to <em>Aus GLAMR</em>.</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -205,7 +205,6 @@ class CommandsTestCase(TestCase):
|
||||||
# should not be announced
|
# should not be announced
|
||||||
self.assertEqual(models.Announcement.objects.count(), 0)
|
self.assertEqual(models.Announcement.objects.count(), 0)
|
||||||
|
|
||||||
|
|
||||||
def test_check_feeds_exclude_tag(self):
|
def test_check_feeds_exclude_tag(self):
|
||||||
"""test parse a feed with exclude tag"""
|
"""test parse a feed with exclude tag"""
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ from operator import attrgetter
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
|
from django.contrib.postgres.aggregates import ArrayAgg
|
||||||
from django.contrib.postgres.search import SearchRank, SearchVector
|
from django.contrib.postgres.search import SearchRank, SearchVector
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.core.mail import EmailMessage
|
from django.core.mail import EmailMessage
|
||||||
|
@ -34,12 +35,21 @@ class HomeFeed(View):
|
||||||
class Blogs(View):
|
class Blogs(View):
|
||||||
"""browse the list of blogs"""
|
"""browse the list of blogs"""
|
||||||
|
|
||||||
def get(self, request):
|
def get(self, request, category=None):
|
||||||
"""here they are"""
|
"""here they are"""
|
||||||
|
|
||||||
|
if category:
|
||||||
|
|
||||||
|
blogs = models.Blog.objects.filter(approved=True, active=True, category=category).order_by(
|
||||||
|
"-updateddate"
|
||||||
|
)
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
blogs = models.Blog.objects.filter(approved=True, active=True).order_by(
|
blogs = models.Blog.objects.filter(approved=True, active=True).order_by(
|
||||||
"-updateddate"
|
"-updateddate"
|
||||||
)
|
)
|
||||||
|
|
||||||
for blog in blogs:
|
for blog in blogs:
|
||||||
blog.category_name = models.Category(blog.category).label
|
blog.category_name = models.Category(blog.category).label
|
||||||
data = {"title": "Blogs and websites", "blogs": blogs}
|
data = {"title": "Blogs and websites", "blogs": blogs}
|
||||||
|
@ -49,18 +59,22 @@ class Blogs(View):
|
||||||
class Conferences(View):
|
class Conferences(View):
|
||||||
"""browse the list of conferences"""
|
"""browse the list of conferences"""
|
||||||
|
|
||||||
def get(self, request):
|
def get(self, request, category=None):
|
||||||
"""here they are"""
|
"""here they are"""
|
||||||
now = timezone.now()
|
now = timezone.now()
|
||||||
|
|
||||||
|
if category:
|
||||||
|
cons = models.Event.objects.filter(approved=True, start_date__gte=now, category=category).order_by(
|
||||||
|
"start_date"
|
||||||
|
)
|
||||||
|
else:
|
||||||
cons = models.Event.objects.filter(approved=True, start_date__gte=now).order_by(
|
cons = models.Event.objects.filter(approved=True, start_date__gte=now).order_by(
|
||||||
"start_date"
|
"start_date"
|
||||||
)
|
)
|
||||||
|
|
||||||
for con in cons:
|
for con in cons:
|
||||||
con.category_name = models.Category(con.category).label
|
con.category_name = models.Category(con.category).label
|
||||||
con.call_for_papers = con.cfp.all().last()
|
con.call_for_papers = con.cfp.filter(closing_date__gte=timezone.now()).order_by("-closing_date").last()
|
||||||
if con.call_for_papers and (con.call_for_papers.closing_date > now.date()):
|
|
||||||
date = con.call_for_papers.closing_date.strftime("%a %d %b %Y")
|
|
||||||
con.call_for_papers = f"{con.call_for_papers.name} closes {date}"
|
|
||||||
|
|
||||||
data = {"title": "Upcoming events", "cons": cons}
|
data = {"title": "Upcoming events", "cons": cons}
|
||||||
return render(request, "browse/events.html", data)
|
return render(request, "browse/events.html", data)
|
||||||
|
@ -82,9 +96,15 @@ class CallsForPapers(View):
|
||||||
class Groups(View):
|
class Groups(View):
|
||||||
"""browse the list of groups"""
|
"""browse the list of groups"""
|
||||||
|
|
||||||
def get(self, request):
|
def get(self, request, category=None):
|
||||||
"""here they are"""
|
"""here they are"""
|
||||||
|
|
||||||
|
if category:
|
||||||
|
groups = models.Group.objects.filter(approved=True, category=category).order_by("name")
|
||||||
|
|
||||||
|
else:
|
||||||
groups = models.Group.objects.filter(approved=True).order_by("name")
|
groups = models.Group.objects.filter(approved=True).order_by("name")
|
||||||
|
|
||||||
for group in groups:
|
for group in groups:
|
||||||
group.category_name = models.Category(group.category).label
|
group.category_name = models.Category(group.category).label
|
||||||
group.reg_type = models.utils.GroupType(group.type).label
|
group.reg_type = models.utils.GroupType(group.type).label
|
||||||
|
@ -188,17 +208,7 @@ class RegisterConference(View):
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
conf = form.save()
|
conf = form.save()
|
||||||
send_email("event", conf)
|
send_email("event", conf)
|
||||||
cfp_form = forms.RegisterCallForPapersForm({"event": conf.id})
|
return redirect("/thankyou/conference")
|
||||||
data = {
|
|
||||||
"title": "Register your Call for Papers",
|
|
||||||
"form": cfp_form,
|
|
||||||
"conf_name": conf.name,
|
|
||||||
}
|
|
||||||
|
|
||||||
return render(request, "events/cfp.html", data)
|
|
||||||
|
|
||||||
data = {"title": "Complete blog registration", "form": form, "errors": True}
|
|
||||||
return render(request, "events/register.html", data)
|
|
||||||
|
|
||||||
|
|
||||||
class RegisterCallForPapers(View):
|
class RegisterCallForPapers(View):
|
||||||
|
@ -292,13 +302,16 @@ class Search(View):
|
||||||
query = request.GET.get("q")
|
query = request.GET.get("q")
|
||||||
|
|
||||||
article_vector = (
|
article_vector = (
|
||||||
SearchVector("tags__name", weight="A")
|
SearchVector("tagnames", weight="A")
|
||||||
+ SearchVector("title", weight="B")
|
+ SearchVector("title", weight="B")
|
||||||
+ SearchVector("description", weight="C")
|
+ SearchVector("description", weight="C")
|
||||||
)
|
)
|
||||||
|
|
||||||
articles = (
|
articles = (
|
||||||
models.Article.objects.annotate(rank=SearchRank(article_vector, query))
|
models.Article.objects.annotate(
|
||||||
|
tagnames=ArrayAgg("tags__name", distinct=True), # see above: this prevents many-to-many objects like tags causing the same article to appear in the results multiple times
|
||||||
|
rank=SearchRank(article_vector, query)
|
||||||
|
)
|
||||||
.filter(rank__gte=0.1)
|
.filter(rank__gte=0.1)
|
||||||
.order_by("-rank")
|
.order_by("-rank")
|
||||||
)
|
)
|
||||||
|
@ -308,7 +321,8 @@ class Search(View):
|
||||||
)
|
)
|
||||||
|
|
||||||
events = (
|
events = (
|
||||||
models.Event.objects.filter(approved=True).annotate(rank=SearchRank(conference_vector, query))
|
models.Event.objects.filter(approved=True)
|
||||||
|
.annotate(rank=SearchRank(conference_vector, query))
|
||||||
.filter(rank__gte=0.1)
|
.filter(rank__gte=0.1)
|
||||||
.order_by("-rank")
|
.order_by("-rank")
|
||||||
)
|
)
|
||||||
|
@ -318,7 +332,8 @@ class Search(View):
|
||||||
)
|
)
|
||||||
|
|
||||||
cfps = (
|
cfps = (
|
||||||
models.CallForPapers.objects.filter(approved=True).annotate(rank=SearchRank(cfp_vector, query))
|
models.CallForPapers.objects.filter(approved=True)
|
||||||
|
.annotate(rank=SearchRank(cfp_vector, query))
|
||||||
.filter(rank__gte=0.1)
|
.filter(rank__gte=0.1)
|
||||||
.order_by("-rank")
|
.order_by("-rank")
|
||||||
)
|
)
|
||||||
|
@ -328,7 +343,8 @@ class Search(View):
|
||||||
)
|
)
|
||||||
|
|
||||||
newsletters = (
|
newsletters = (
|
||||||
models.Newsletter.objects.filter(approved=True).annotate(rank=SearchRank(news_vector, query))
|
models.Newsletter.objects.filter(approved=True)
|
||||||
|
.annotate(rank=SearchRank(news_vector, query))
|
||||||
.filter(rank__gte=0.1)
|
.filter(rank__gte=0.1)
|
||||||
.order_by("-rank")
|
.order_by("-rank")
|
||||||
)
|
)
|
||||||
|
@ -338,7 +354,8 @@ class Search(View):
|
||||||
)
|
)
|
||||||
|
|
||||||
groups = (
|
groups = (
|
||||||
models.Event.objects.filter(approved=True).annotate(rank=SearchRank(group_vector, query))
|
models.Group.objects.filter(approved=True)
|
||||||
|
.annotate(rank=SearchRank(group_vector, query))
|
||||||
.filter(rank__gte=0.1)
|
.filter(rank__gte=0.1)
|
||||||
.order_by("-rank")
|
.order_by("-rank")
|
||||||
)
|
)
|
||||||
|
|
|
@ -11,8 +11,8 @@ services:
|
||||||
web:
|
web:
|
||||||
build: .
|
build: .
|
||||||
env_file: .env
|
env_file: .env
|
||||||
# command: python manage.py runserver 0.0.0.0:8000
|
command: python manage.py runserver 0.0.0.0:8000
|
||||||
command: gunicorn --env DJANGO_SETTINGS_MODULE=ausglamr.settings ausglamr.wsgi --workers=10 --threads=4 -b 0.0.0.0:8000
|
# command: gunicorn --env DJANGO_SETTINGS_MODULE=ausglamr.settings ausglamr.wsgi --workers=10 --threads=4 -b 0.0.0.0:8000
|
||||||
volumes:
|
volumes:
|
||||||
- .:/app
|
- .:/app
|
||||||
depends_on:
|
depends_on:
|
||||||
|
|
|
@ -30,6 +30,11 @@ case "$CMD" in
|
||||||
announce)
|
announce)
|
||||||
runweb python manage.py announce
|
runweb python manage.py announce
|
||||||
;;
|
;;
|
||||||
|
backup)
|
||||||
|
/snap/bin/docker exec -u root ausglamr_db_1 pg_dump -v -Fc -U ausglamr -d "ausglamr" -f /tmp/ausglamr_backup.dump
|
||||||
|
/snap/bin/docker cp ausglamr_db_1:/tmp/ausglamr_backup.dump /home/hugh/backups/
|
||||||
|
mv /home/hugh/backups/ausglamr_backup.dump /home/hugh/backups/ausglamr_backup_$(date +'%a').dump
|
||||||
|
;;
|
||||||
black)
|
black)
|
||||||
docker compose run --rm web black ausglamr blogs
|
docker compose run --rm web black ausglamr blogs
|
||||||
;;
|
;;
|
||||||
|
|
Loading…
Reference in a new issue