Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a field to specify reviewers when submitting a new feed item #62

Merged
merged 4 commits into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions qgisfeedproject/qgisfeed/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from .models import CharacterLimitConfiguration, QgisFeedEntry
from .languages import LANGUAGES
from django.utils import timezone
from django.contrib.auth.models import User

class HomePageFilterForm(forms.Form):
"""
Expand Down Expand Up @@ -81,6 +82,16 @@ class FeedItemForm(forms.ModelForm):
"""
Form for feed entry add or update
"""

sticky = forms.BooleanField(
required=False,
widget=forms.CheckboxInput(attrs={'class': 'checkbox'})
)

approvers = forms.MultipleChoiceField(
required=False,
widget=forms.SelectMultiple()
)
class Meta:
model = QgisFeedEntry
fields = [
Expand Down Expand Up @@ -127,6 +138,7 @@ def __init__(self, *args, **kwargs):
}
)
self.fields['publish_to'].initial = timezone.now() + timezone.timedelta(days=30)
self.fields['approvers'].choices = self.get_approvers_choices()

def clean_content(self):
content = self.cleaned_data['content']
Expand All @@ -142,8 +154,11 @@ def clean_content(self):
)
return content

def get_approvers_choices(self):

sticky = forms.BooleanField(
required=False,
widget=forms.CheckboxInput(attrs={'class': 'checkbox'})
)
return (
(u.pk, u.username) for u in User.objects.filter(
is_active=True,
email__isnull=False
).exclude(email='') if u.has_perm("qgisfeed.publish_qgisfeedentry")
)
40 changes: 38 additions & 2 deletions qgisfeedproject/qgisfeed/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from django.core.files.uploadedfile import SimpleUploadedFile
from django.conf import settings
from django.db import connection
from django.core import mail

from .utils import get_field_max_length

Expand All @@ -35,7 +36,6 @@

from os.path import join


class MockRequest:

def build_absolute_uri(self, uri):
Expand Down Expand Up @@ -423,6 +423,14 @@ def test_authenticated_user_access(self):
self.assertTemplateUsed(response, 'feeds/feed_item_form.html')
self.assertTrue('form' in response.context)

# Check if the approver has the permission.
# Here, only the the admin user is listed.
approvers = response.context['form']['approvers']
self.assertEqual(len(approvers), 1)
approver_id = int(approvers[0].data['value'])
approver = User.objects.get(pk=approver_id)
self.assertTrue(approver.has_perm("qgisfeed.publish_qgisfeedentry"))

# Access the feed_entry_update view after logging in
response = self.client.get(reverse('feed_entry_update', args=[3]))
self.assertEqual(response.status_code, 200)
Expand Down Expand Up @@ -625,11 +633,39 @@ def test_get_field_max_length(self):
# Test the get_field_max_length function
content_max_length = get_field_max_length(CharacterLimitConfiguration, field_name="content")
self.assertEqual(content_max_length, 500)

CharacterLimitConfiguration.objects.create(
field_name="content",
max_characters=1000
)
content_max_length = get_field_max_length(CharacterLimitConfiguration, field_name="content")
self.assertEqual(content_max_length, 1000)

def test_add_feed_with_reviewer(self):
# Add a feed entry with specified reviewer test
self.client.login(username='staff', password='staff')
spatial_filter = Polygon(((0, 0), (0, 1), (1, 1), (1, 0), (0, 0)))
image_path = join(settings.MEDIA_ROOT, "feedimages", "rust.png")

post_data = {
'title': 'QGIS core will be rewritten in Rust',
'image': open(image_path, "rb"),
'content': '<p>Tired with C++ intricacies, the core developers have decided to rewrite QGIS in <strong>Rust</strong>',
'url': 'https://www.null.com',
'sticky': False,
'sorting': 0,
'language_filter': 'en',
'spatial_filter': str(spatial_filter),
'publish_from': '2023-10-18 14:46:00+00',
'publish_to': '2023-10-29 14:46:00+00',
'reviewers': [1]
}

response = self.client.post(reverse('feed_entry_add'), data=post_data)
self.assertEqual(response.status_code, 302)
self.assertRedirects(response, reverse('feeds_list'))

self.assertEqual(
mail.outbox[0].recipients(),
['[email protected]']
)

38 changes: 17 additions & 21 deletions qgisfeedproject/qgisfeed/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from django.urls import reverse
from django.conf import settings
from django.core.mail import EmailMultiAlternatives
from django.core.mail import send_mail
from django.contrib.gis.db.models import Model

Expand All @@ -19,31 +20,26 @@ def simplify(text: str) -> str:
return str(text)


def notify_admin(author, request, recipients, obj):
def notify_reviewers(author, request, recipients, cc, obj):
"""Send notification emails"""
body = """
User %s added a new entry.\r\n
Title: %s\r\n
Link: %s\r\n
""" % (
author.username,
obj.title,
request.build_absolute_uri(reverse('feed_entry_update', args=(obj.pk,)))
)
if settings.DEBUG:
logger.debug("DEBUG is True: email not sent:\n %s" % body)
else:
send_mail(
'A QGIS News Entry was added: %s' % obj.title,
body,
QGISFEED_FROM_EMAIL,
recipients,
fail_silently=True
)
body = f"""
Hi, \r\n
{author.username} asked you to review the feed entry available at {request.build_absolute_uri(reverse('feed_entry_update', args=(obj.pk,)))}
Title: {obj.title}\r\n
Your beloved QGIS Feed bot.
"""
msg = EmailMultiAlternatives(
'QGIS feed entry review requested by %s' % author.username,
body,
QGISFEED_FROM_EMAIL,
recipients,
cc=cc,
)
msg.send(fail_silently=True)

def get_field_max_length(ConfigurationModel: Model, field_name: str):
try:
config = ConfigurationModel.objects.get(field_name=field_name)
return config.max_characters
except ConfigurationModel.DoesNotExist:
return 500
return 500
32 changes: 27 additions & 5 deletions qgisfeedproject/qgisfeed/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
from django.contrib.auth.models import User

from .forms import FeedEntryFilterForm, FeedItemForm, HomePageFilterForm
from .utils import get_field_max_length, notify_admin
from .utils import get_field_max_length, notify_reviewers
from .models import QgisFeedEntry, CharacterLimitConfiguration
from .languages import LANGUAGE_KEYS
import json
Expand Down Expand Up @@ -294,10 +294,32 @@ def post(self, request):
new_object.save()
success = True

if not request.user.is_superuser:
recipients = [u.email for u in User.objects.filter(is_superuser=True, is_active=True, email__isnull=False).exclude(email='')]
if recipients:
notify_admin(request.user, request, recipients, new_object)
# If at least one reviewer is specified,
# set the specified reviewers as recipients
# and cc the other reviewers.
# Otherwise, send the email to all reviewers.
reviewers = User.objects.filter(
is_active=True,
email__isnull=False
).exclude(email='')

recipients = [
u.email for u in reviewers if u.has_perm("qgisfeed.publish_qgisfeedentry")
]
cc_list = []
if form.cleaned_data.get("approvers") and len(form.cleaned_data.get("approvers")) > 0:
approver_ids = form.cleaned_data.get("approvers")
recipients = [
u.email for u in reviewers.filter(
pk__in=approver_ids
) if u.has_perm("qgisfeed.publish_qgisfeedentry")
]
cc_list = [
u.email for u in reviewers.exclude(pk__in=approver_ids) if u.has_perm("qgisfeed.publish_qgisfeedentry")
]

if recipients and len(recipients) > 0:
notify_reviewers(request.user, request, recipients, cc_list, new_object)

return redirect('feeds_list')
else:
Expand Down
Binary file added qgisfeedproject/static/js/chosen-sprite.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added qgisfeedproject/static/js/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions qgisfeedproject/static/js/chosen.jquery.min.js

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions qgisfeedproject/static/js/chosen.min.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading