Skip to content

Commit b8c8f01

Browse files
committed
Finished blocklist and added enable status to types
1 parent 53e0199 commit b8c8f01

18 files changed

+331
-35
lines changed

application/emails.py

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from django.urls import reverse
2+
3+
from app.emails import Email
4+
5+
6+
def send_email_to_blocked_admins(request, users, application, blocked_user):
7+
url = request.build_absolute_uri(reverse('change_status_application', kwargs={
8+
'uuid': application.get_uuid, 'status': application.STATUS_PENDING
9+
}))
10+
context = {
11+
'application': application,
12+
'blocked_user': blocked_user,
13+
'url': url,
14+
}
15+
Email(name='new_blocked', context=context, to=users, request=request).send()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Generated by Django 4.0.4 on 2022-08-23 13:14
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('application', '0008_application_last_modified'),
10+
]
11+
12+
operations = [
13+
migrations.AlterModelOptions(
14+
name='application',
15+
options={'permissions': (('can_review_application', 'Can review application'), ('can_invite_application', 'Can invite application'), ('can_review_dubious_application', 'Can review dubious application'), ('can_review_blocked_application', 'Can review blocked application'))},
16+
),
17+
migrations.AlterField(
18+
model_name='application',
19+
name='status',
20+
field=models.CharField(choices=[('P', 'Under review'), ('R', 'Wait listed'), ('I', 'Invited'), ('LR', 'Last reminder'), ('C', 'Confirmed'), ('X', 'Cancelled'), ('A', 'Attended'), ('E', 'Expired'), ('D', 'Dubious'), ('IV', 'Invalid'), ('BL', 'Blocked'), ('NC', 'Needs change')], default='P', max_length=2),
21+
),
22+
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Generated by Django 4.0.4 on 2022-08-23 18:07
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('application', '0009_alter_application_options_alter_application_status'),
10+
]
11+
12+
operations = [
13+
migrations.RemoveField(
14+
model_name='applicationtypeconfig',
15+
name='needs_confirmation',
16+
),
17+
migrations.RemoveField(
18+
model_name='applicationtypeconfig',
19+
name='review',
20+
),
21+
migrations.AddField(
22+
model_name='applicationtypeconfig',
23+
name='auto_blocklist',
24+
field=models.BooleanField(default=True, help_text='Applications pass test of blocklist table on apply'),
25+
),
26+
migrations.AddField(
27+
model_name='applicationtypeconfig',
28+
name='auto_confirm',
29+
field=models.BooleanField(default=False, help_text='Applications set on status confirmed by default'),
30+
),
31+
migrations.AddField(
32+
model_name='applicationtypeconfig',
33+
name='dubious',
34+
field=models.BooleanField(default=True, help_text='Dubious reviewing system'),
35+
),
36+
migrations.AddField(
37+
model_name='applicationtypeconfig',
38+
name='vote',
39+
field=models.BooleanField(default=True, help_text='Activate voting system'),
40+
),
41+
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Generated by Django 4.0.4 on 2022-08-23 18:10
2+
3+
from django.db import migrations
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('application', '0010_remove_applicationtypeconfig_needs_confirmation_and_more'),
10+
]
11+
12+
operations = [
13+
migrations.RenameField(
14+
model_name='applicationtypeconfig',
15+
old_name='auto_blocklist',
16+
new_name='blocklist',
17+
),
18+
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Generated by Django 4.0.4 on 2022-08-23 18:35
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('application', '0011_rename_auto_blocklist_applicationtypeconfig_blocklist'),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name='applicationtypeconfig',
15+
name='compatible_with_others',
16+
field=models.BooleanField(default=False, help_text='User can confirm in more than one type'),
17+
),
18+
]

application/models.py

+23-9
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,17 @@ class ApplicationTypeConfig(models.Model):
3232
start_application_date = models.DateTimeField(default=timezone.now, null=True)
3333
end_application_date = models.DateTimeField(default=timezone.now, null=True)
3434
group = models.ForeignKey(Group, on_delete=models.DO_NOTHING)
35-
review = models.BooleanField(default=True)
36-
needs_confirmation = models.BooleanField(default=False)
35+
vote = models.BooleanField(default=True, help_text=_('Activate voting system'))
36+
dubious = models.BooleanField(default=True, help_text=_('Dubious reviewing system'))
37+
blocklist = models.BooleanField(default=True, help_text=_('Applications pass test of blocklist table on apply'))
38+
auto_confirm = models.BooleanField(default=False, help_text=_('Applications set on status confirmed by default'))
39+
compatible_with_others = models.BooleanField(default=False, help_text=_('User can confirm in more than one type'))
40+
41+
def vote_enabled(self):
42+
return self.vote and not self.auto_confirm
43+
44+
def dubious_enabled(self):
45+
return self.dubious and not self.auto_confirm
3746

3847
@property
3948
def get_token(self):
@@ -86,7 +95,7 @@ class Application(models.Model):
8695
STATUS_DUBIOUS = 'D'
8796
STATUS_NEEDS_CHANGE = 'NC'
8897
STATUS_INVALID = 'IV'
89-
STATUS_BLACKLISTED = 'BL'
98+
STATUS_BLOCKED = 'BL'
9099
STATUS = [
91100
(STATUS_PENDING, _('Under review')),
92101
(STATUS_REJECTED, _('Wait listed')),
@@ -98,7 +107,7 @@ class Application(models.Model):
98107
(STATUS_EXPIRED, _('Expired')),
99108
(STATUS_DUBIOUS, _('Dubious')),
100109
(STATUS_INVALID, _('Invalid')),
101-
(STATUS_BLACKLISTED, _('Blacklisted')),
110+
(STATUS_BLOCKED, _('Blocked')),
102111
(STATUS_NEEDS_CHANGE, _('Needs change')),
103112
]
104113
STATUS_COLORS = {
@@ -113,7 +122,7 @@ class Application(models.Model):
113122
STATUS_EXPIRED: 'danger',
114123
STATUS_INVALID: 'danger',
115124
STATUS_REJECTED: 'danger',
116-
STATUS_BLACKLISTED: 'danger',
125+
STATUS_BLOCKED: 'danger',
117126
}
118127
STATUS_DESCRIPTION = {
119128
STATUS_NEEDS_CHANGE: _('Your application might have some misleading information. '
@@ -127,7 +136,7 @@ class Application(models.Model):
127136
STATUS_EXPIRED: _('Your application have been expired. Please contact us quick if you want to come.'),
128137
STATUS_INVALID: _('Your application have been invalidated. It seems you cannot join us with this role.'),
129138
STATUS_REJECTED: _('We are so sorry, but our hack is full...'),
130-
STATUS_BLACKLISTED: _('User was blacklisted by your organization.'),
139+
STATUS_BLOCKED: _('User was blocked by your organization.'),
131140
STATUS_DUBIOUS: _('This application has something suspicious'),
132141
STATUS_ATTENDED: _('You have arrived at the event. Have fun!'),
133142
}
@@ -162,14 +171,15 @@ def form_data(self):
162171

163172
def set_status(self, status):
164173
self.status = status
174+
self.status_changed = True
165175
self.status_update_date = timezone.now()
166176

167177
@form_data.setter
168178
def form_data(self, data):
169179
self.data = json.dumps(data)
170180

171181
def __str__(self):
172-
return self.user.email
182+
return '%s: %s' % (self.type.name, self.user.email)
173183

174184
@property
175185
def get_uuid(self):
@@ -180,7 +190,7 @@ def get_public_status_display(self):
180190
return [y for (x, y) in self.STATUS if x == status][0]
181191

182192
def get_public_status(self):
183-
if self.status in [self.STATUS_BLACKLISTED, self.STATUS_DUBIOUS]:
193+
if self.status in [self.STATUS_BLOCKED, self.STATUS_DUBIOUS]:
184194
return self.STATUS_PENDING
185195
return self.status
186196

@@ -218,7 +228,10 @@ def can_edit(self):
218228
return self.status in [self.STATUS_PENDING, self.STATUS_NEEDS_CHANGE]
219229

220230
def save(self, *args, **kwargs):
221-
self.last_modified = timezone.now()
231+
if getattr(self, 'status_changed', False):
232+
self.last_modified = self.status_update_date
233+
else:
234+
self.last_modified = timezone.now()
222235
super().save(*args, **kwargs)
223236

224237
class Meta:
@@ -227,6 +240,7 @@ class Meta:
227240
('can_review_application', _('Can review application')),
228241
('can_invite_application', _('Can invite application')),
229242
('can_review_dubious_application', _('Can review dubious application')),
243+
('can_review_blocked_application', _('Can review blocked application')),
230244
)
231245

232246

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{% extends 'mails/base.html' %}
2+
{% block content %}
3+
<p>Hi there,</p>
4+
<p>I have found that one of the applications may be from one of the users on the Blocked List.</p>
5+
<br>
6+
<p><strong>{{ application.type.name }} application user:</strong></p>
7+
<ul>
8+
<li><strong>Name:</strong> {{ application.user.get_full_name }}</li>
9+
<li><strong>Email:</strong> {{ application.user.email }}</li>
10+
</ul>
11+
<br>
12+
<p><strong>Blocked list user:</strong></p>
13+
<ul>
14+
<li><strong>Name:</strong> {{ blocked_user.full_name }}</li>
15+
<li><strong>Email:</strong> {{ blocked_user.email }}</li>
16+
</ul>
17+
<br>
18+
<p>If this is an error you can change it to Under Review status by clicking Clear status.</p>
19+
20+
{% include 'mails/components/button.html' with url=url text='Clear status' %}
21+
22+
<p>Best regards,</p>
23+
<p>{{ app_name }}.</p>
24+
{% endblock %}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
New {{ application.type.name }} application blocked

application/views.py

+25-1
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,23 @@
11
from django.contrib import messages
2+
from django.contrib.auth import get_user_model
23
from django.contrib.auth.models import Group
34
from django.core.exceptions import PermissionDenied
45
from django.core.files.storage import FileSystemStorage
56
from django.db import transaction
67
from django.http import Http404, HttpResponse
78
from django.shortcuts import get_object_or_404, redirect
89
from django.urls import reverse
10+
from django.utils import timezone
911
from django.views import View
1012
from django.views.generic import TemplateView
1113
from django.utils.translation import gettext as _
1214

1315
from application import forms
16+
from application.emails import send_email_to_blocked_admins
1417
from application.models import Application, ApplicationTypeConfig, ApplicationLog
1518
from user.forms import UserProfileForm
1619
from user.mixins import LoginRequiredMixin
20+
from user.models import BlockedUser
1721

1822

1923
class ApplicationHome(LoginRequiredMixin, TemplateView):
@@ -65,15 +69,31 @@ def get_context_data(self, **kwargs):
6569
'application_type': application_type, 'user_form': user_form, 'public': self.public})
6670
return context
6771

72+
def block_application(self, user, application):
73+
blocked_user = BlockedUser.get_blocked(full_name=user.get_full_name(), email=user.email)
74+
application.status = Application.STATUS_BLOCKED
75+
User = get_user_model()
76+
perms = ['can_review_blocked_application', 'can_review_blocked_application_%s' %
77+
application.type.name.lower()]
78+
users_emails = User.get_users_with_permissions(perms).values_list('email', flat=True)
79+
send_email_to_blocked_admins(self.request, users_emails, application=application, blocked_user=blocked_user)
80+
6881
def save_application(self, form, app_type, user):
6982
try:
7083
if not self.public:
7184
raise Application.DoesNotExist()
72-
Application.objects.get(user=user, type__name__iexact=self.request.GET.get('type', 'Hacker').lower())
85+
Application.objects.get(user=user, type_id=app_type.pk)
7386
except Application.DoesNotExist:
7487
instance = form.save(commit=False)
7588
instance.user = user
7689
instance.type_id = app_type.pk
90+
if app_type.auto_confirm:
91+
instance.status = Application.STATUS_CONFIRMED
92+
if app_type.blocklist:
93+
try:
94+
self.block_application(user, application=instance)
95+
except BlockedUser.DoesNotExist:
96+
pass
7797
with transaction.atomic():
7898
instance.save()
7999
form.save_files(instance=instance)
@@ -245,4 +265,8 @@ def get(self, request, **kwargs):
245265
if new_status == Application.STATUS_ATTENDED:
246266
group = Group.objects.get_or_create(application.type.name)
247267
group.user_set.add(application.user)
268+
if new_status == application.STATUS_CONFIRMED:
269+
Application.objects.exclude(uuid=application.get_uuid)\
270+
.filter(user=application.user, type__compatible_with_others=False)\
271+
.update(status=Application.STATUS_CANCELLED, status_update_date=timezone.now())
248272
return redirect(next_page)

review/migrations/0003_blockedlist.py

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Generated by Django 4.0.4 on 2022-08-23 12:16
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('review', '0002_alter_vote_calculated_vote'),
10+
]
11+
12+
operations = [
13+
migrations.CreateModel(
14+
name='BlockedList',
15+
fields=[
16+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
17+
('full_name', models.CharField(max_length=100)),
18+
('email', models.EmailField(max_length=100)),
19+
],
20+
),
21+
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Generated by Django 4.0.4 on 2022-08-23 12:19
2+
3+
from django.db import migrations
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('review', '0003_blockedlist'),
10+
]
11+
12+
operations = [
13+
migrations.DeleteModel(
14+
name='BlockedList',
15+
),
16+
]

review/templates/application_detail.html

+12-2
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ <h2>{% translate 'Score' %}</h2>
211211
});
212212
});
213213
</script>
214-
{% elif perms|add_type:application.type.name|has_application_perm:'can_review_dubious_application' and application.status == application.STATUS_DUBIOUS or application.status == application.STATUS_NEEDS_CHANGE %}
214+
{% elif application.type.dubious_enabled and perms|add_type:application.type.name|has_application_perm:'can_review_dubious_application' and application.status == application.STATUS_DUBIOUS or application.status == application.STATUS_NEEDS_CHANGE %}
215215
<form method="post" class="mt-2">
216216
<h3>{% if application.status == application.STATUS_DUBIOUS %}{% translate 'Dubious form' %}{% else %}{% translate 'Correction form' %}{% endif %}</h3>
217217
{% csrf_token %}
@@ -225,8 +225,15 @@ <h3>{% if application.status == application.STATUS_DUBIOUS %}{% translate 'Dubio
225225
</div>
226226
</form>
227227
{% endif %}
228+
{% if application.type.blocklist and blocked_user %}
229+
<h2>{% translate 'Blocked user:' %}</h2>
230+
<ul>
231+
<li><strong>{% translate 'Name:' %}</strong> {{ blocked_user.full_name }}</li>
232+
<li><strong>{% translate 'Email:' %}</strong> {{ blocked_user.email }}</li>
233+
</ul>
234+
{% endif %}
228235
<div class="d-grid gap-2 col-lg-6 mx-auto mt-2">
229-
{% if application.status != application.STATUS_DUBIOUS and application.status != application.STATUS_NEEDS_CHANGE %}
236+
{% if application.type.dubious_enabled and application.status != application.STATUS_DUBIOUS and application.status != application.STATUS_NEEDS_CHANGE and application.status != application.STATUS_BLOCKED %}
230237
<button class="btn btn-warning" onclick="mark_dubious()">{% translate 'Mark as dubious' %}</button>
231238
<script>
232239
function mark_dubious() {
@@ -236,6 +243,9 @@ <h3>{% if application.status == application.STATUS_DUBIOUS %}{% translate 'Dubio
236243
}
237244
</script>
238245
{% endif %}
246+
{% if application.type.blocklist and application.status == application.STATUS_BLOCKED and perms|add_type:application.type.name|has_application_perm:'can_review_blocked_application' %}
247+
<a class="btn btn-primary" href="{% url 'change_status_application' application.get_uuid application.STATUS_PENDING %}?next={{ request.get_path }}" onclick="return confirm('{% translate "This application will be unblocked. Are you sure?" %}')">{% translate 'This should not be blocked' %}</a>
248+
{% endif %}
239249
</div>
240250
</div>
241251
{% else %}

0 commit comments

Comments
 (0)