Skip to content
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
4 changes: 3 additions & 1 deletion accounts/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from django.contrib.auth.decorators import login_required

from .models import CustomUser, Organisation
from accounts.models import SlackSiteSettings


class CustomUserAdmin(BaseUserAdmin):
Expand Down Expand Up @@ -38,7 +39,7 @@ class CustomUserAdmin(BaseUserAdmin):

form = UserChangeForm
add_form = UserCreationForm
list_display = ('email', 'full_name', 'is_superuser', 'user_type',
list_display = ('email', 'username', 'full_name', 'is_superuser', 'user_type',
'is_external')
list_filter = ('is_staff', 'is_superuser', 'is_active', 'groups',
'is_external')
Expand All @@ -52,3 +53,4 @@ class CustomUserAdmin(BaseUserAdmin):
admin.site.login = login_required(admin.site.login)
admin.site.register(CustomUser, CustomUserAdmin)
admin.site.register(Organisation)
admin.site.register(SlackSiteSettings)
27 changes: 27 additions & 0 deletions accounts/migrations/0018_slacksitesettings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Generated by Django 3.1.13 on 2022-12-19 14:45

from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('accounts', '0017_customuser_timezone'),
]

operations = [
migrations.CreateModel(
name='SlackSiteSettings',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('enable_welcome_emails', models.BooleanField(default=True)),
('communication_channel_type', models.CharField(choices=[('slack_private_channel', 'Private Slack Channel'), ('other', 'Other')], default='slack_private_channel', max_length=50)),
('slack_admins', models.ManyToManyField(related_name='slacksitesettings', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'Slack Site Settings',
'verbose_name_plural': 'Slack Site Settings',
},
),
]
30 changes: 30 additions & 0 deletions accounts/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,14 @@
from django.contrib.auth.models import AbstractUser

from .lists import LMS_MODULES_CHOICES, TIMEZONE_CHOICES
from main.models import SingletonModel
from teams.lists import LMS_LEVELS

COMMUNICATION_CHANNEL_TYPES = [
('slack_private_channel', 'Private Slack Channel'),
('other', 'Other'),
]


class UserType(Enum):
SUPERUSER = 0
Expand Down Expand Up @@ -144,6 +150,13 @@ def participant_label(self):
return 'Hackathon Enthusiast'
else:
return 'Hackathon Veteran'

def is_participant(self, hackathon):
if not hackathon:
return False

return self in hackathon.participants.all()


@property
def user_type(self):
Expand Down Expand Up @@ -180,3 +193,20 @@ def user_type(self):
else:
# A non-specified group
return None


class SlackSiteSettings(SingletonModel):
""" Model to set how the showcase should be constructed"""
slack_admins = models.ManyToManyField(CustomUser,
related_name="slacksitesettings")
enable_welcome_emails = models.BooleanField(default=True)
communication_channel_type = models.CharField(
max_length=50, choices=COMMUNICATION_CHANNEL_TYPES,
default='slack_private_channel')

def __str__(self):
return "Slack Settings"

class Meta:
verbose_name = 'Slack Site Settings'
verbose_name_plural = 'Slack Site Settings'
21 changes: 21 additions & 0 deletions competencies/migrations/0003_auto_20221219_1421.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Generated by Django 3.1.13 on 2022-12-19 14:21

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('competencies', '0002_auto_20220808_1029'),
]

operations = [
migrations.AlterModelOptions(
name='competencyassessment',
options={'verbose_name': 'Competency Self Assessment', 'verbose_name_plural': 'Competency Self Assessments'},
),
migrations.AlterModelOptions(
name='competencyassessmentrating',
options={'verbose_name': 'Competency Self Assessment Rating', 'verbose_name_plural': 'Competency Self Assessment Ratings'},
),
]
18 changes: 18 additions & 0 deletions hackathon/migrations/0047_auto_20221219_1421.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 3.1.13 on 2022-12-19 14:21

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('hackathon', '0046_auto_20220113_1350'),
]

operations = [
migrations.AlterField(
model_name='hackathon',
name='is_public',
field=models.BooleanField(default=True),
),
]
18 changes: 18 additions & 0 deletions hackathon/migrations/0048_auto_20221219_1655.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 3.1.13 on 2022-12-19 16:55

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('hackathon', '0047_auto_20221219_1421'),
]

operations = [
migrations.AlterField(
model_name='hackteam',
name='communication_channel',
field=models.CharField(blank=True, default='', help_text='Usually a link to the Private Slack Channel, but can be a link to something else.', max_length=255),
),
]
2 changes: 1 addition & 1 deletion hackathon/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ class HackTeam(models.Model):
on_delete=models.SET_NULL)
communication_channel = models.CharField(
default="", max_length=255, blank=True,
help_text=("Usually a link to the Slack group IM, but can be a link "
help_text=("Usually a link to the Private Slack Channel, but can be a link "
"to something else."))

def __str__(self):
Expand Down
3 changes: 3 additions & 0 deletions hackathon/templates/hackathon/hackathon_view.html
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@
<p class="hackathon-sub-details"><i class="far fa-question-circle"></i> Status: {{ hackathon.status }}</p>
<p class="hackathon-sub-details"><i class="fas fa-chalkboard-teacher"></i> Organiser: {{ hackathon.organiser }}</p>
<p class="hackathon-sub-details"><i class="fas fa-users"></i>
Participants: {{ hackathon.participants.all|length }} / Teams: {{ hackathon.teams.all|length }}</p>
</p>
<p class="hackathon-sub-details"><i class="fas fa-user-friends"></i>
Max Participants: {% if hackathon.max_participants %}{{ hackathon.max_participants }}{% else %}Unlimited{% endif %}
{% if hackathon.max_participants_reached %}(Max Reached){% endif %}
</p>
Expand Down
2 changes: 1 addition & 1 deletion hackathon/templates/hackathon/includes/enrollpart.html
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
<a class="ci-link ml-2" href="/teams/{{participant_team.id}}/">{{participant_team}}</a>
</strong>
<div class="mt-2 slack-mpim">
{% include 'includes/create_slack_mpim.html' with team=participant_team button_class='btn btn-sm btn-ci' %}
{% include 'includes/create_slack_private_channel.html' with team=participant_team button_class='btn btn-sm btn-ci' %}
</div>
{% else %}
You have not been assigned a team yet.
Expand Down
4 changes: 2 additions & 2 deletions hackathon/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,13 +360,13 @@ def view_hackathon(request, hackathon_id):
paginator = Paginator(teams, 3)
page = request.GET.get('page')
paged_teams = paginator.get_page(page)
create_group_im = (settings.SLACK_ENABLED and settings.SLACK_BOT_TOKEN)
create_private_channel = (settings.SLACK_ENABLED and settings.SLACK_BOT_TOKEN)

context = {
'hackathon': hackathon,
'teams': paged_teams,
'change_status_form': ChangeHackathonStatusForm(instance=hackathon),
'create_group_im': create_group_im,
'create_private_channel': create_private_channel,
}

return render(request, "hackathon/hackathon_view.html", context)
Expand Down
2 changes: 1 addition & 1 deletion home/models.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from django.db import models

from accounts.models import CustomUser as User
from showcase.models import SingletonModel
from main.models import SingletonModel


class Review(models.Model):
Expand Down
176 changes: 176 additions & 0 deletions home/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@

from django.shortcuts import reverse
from django.test import TestCase
from accounts.models import CustomUser, Organisation
from django.utils import timezone

from hackathon.models import Hackathon


class TestHackathonViews(TestCase):
def setUp(self):
self.organisation = Organisation.objects.create(display_name="CI")
self.partner_org = Organisation.objects.create(display_name="Partner")
self.user = CustomUser.objects.create(username="testuser", organisation=self.organisation)
self.partner_user = CustomUser.objects.create(username="partnertestuser", organisation=self.partner_org)
self.staff_user = CustomUser.objects.create(username="staffuser")
self.staff_user.is_staff = True
self.staff_user.save()
self.super_user = CustomUser.objects.create(username="super_user")
self.super_user.is_staff = True
self.super_user.is_superuser = True
self.super_user.save()
self.hackathon = Hackathon.objects.create(
created_by=self.user,
status='published',
display_name="hacktest",
description="lorem ipsum",
start_date=f'{timezone.now()}',
end_date=f'{timezone.now()}',
organisation=self.organisation,
is_public=True)

def test_list_hackathons_for_non_authenticated_user(self):
hackathon = Hackathon.objects.create(
created_by=self.user,
status='finished',
display_name="hacktest2",
description="lorem ipsum",
start_date=f'{timezone.now()}',
end_date=f'{timezone.now()}',
organisation=self.partner_org,
is_public=False)

hackathon2 = Hackathon.objects.create(
created_by=self.user,
status='published',
display_name="hacktest3",
description="lorem ipsum",
start_date=f'{timezone.now()}',
end_date=f'{timezone.now()}',
organisation=self.partner_org,
is_public=False)

hackathon3 = Hackathon.objects.create(
created_by=self.user,
status='finished',
display_name="hacktest2",
description="lorem ipsum",
start_date=f'{timezone.now()}',
end_date=f'{timezone.now()}',
organisation=self.organisation,
is_public=False)

# if this is more than 5, the response results will have to be paginated
# because they are capped at 5
num_hackathons = Hackathon.objects.count()
self.assertTrue(num_hackathons <= 5)

response = self.client.get(reverse('home'))
recent_hackathons = [hackathon.id for hackathon in response.context['recent_hackathons']]
upcoming_hackathons = [hackathon.id for hackathon in response.context['upcoming_hackathons']]
self.assertEquals(len(recent_hackathons), 0)
self.assertEquals(len(upcoming_hackathons), 1)
self.assertTrue(hackathon.id not in recent_hackathons)
self.assertTrue(hackathon2.id not in upcoming_hackathons)

hackathon3.is_public = True
hackathon3.save()

response = self.client.get(reverse('home'))
recent_hackathons = [hackathon.id for hackathon in response.context['recent_hackathons']]
upcoming_hackathons = [hackathon.id for hackathon in response.context['upcoming_hackathons']]
self.assertEquals(len(recent_hackathons), 1)
self.assertEquals(len(upcoming_hackathons), 1)

hackathon2.is_public = True
hackathon2.save()

response = self.client.get(reverse('home'))
recent_hackathons = [hackathon.id for hackathon in response.context['recent_hackathons']]
upcoming_hackathons = [hackathon.id for hackathon in response.context['upcoming_hackathons']]
self.assertEquals(len(upcoming_hackathons), 2)
self.assertEquals(len(recent_hackathons), 1)

self.user.organisation = self.partner_org
self.user.save()
self.client.force_login(self.user)

response = self.client.get(reverse('home'))
recent_hackathons = [hackathon.id for hackathon in response.context['recent_hackathons']]
upcoming_hackathons = [hackathon.id for hackathon in response.context['upcoming_hackathons']]
self.assertEquals(len(upcoming_hackathons), 2)
self.assertEquals(len(recent_hackathons), 2)

def test_list_partner_hackathons_on_home(self):
hackathon = Hackathon.objects.create(
created_by=self.user,
status='finished',
display_name="hacktest2",
description="lorem ipsum",
start_date=f'{timezone.now()}',
end_date=f'{timezone.now()}',
organisation=self.partner_org,
is_public=False)

hackathon2 = Hackathon.objects.create(
created_by=self.user,
status='published',
display_name="hacktest3",
description="lorem ipsum",
start_date=f'{timezone.now()}',
end_date=f'{timezone.now()}',
organisation=self.partner_org,
is_public=False)

# if this is more than 5, the response results will have to be paginated
# because they are capped at 5
num_hackathons = Hackathon.objects.count()
self.assertTrue(num_hackathons <= 5)

self.client.force_login(self.user)
response = self.client.get(reverse('home'))
recent_hackathons = [hackathon.id for hackathon in response.context['recent_hackathons']]
upcoming_hackathons = [hackathon.id for hackathon in response.context['upcoming_hackathons']]
self.assertTrue(hackathon.id not in recent_hackathons)
self.assertTrue(hackathon2.id not in upcoming_hackathons)

self.client.force_login(self.staff_user)
response = self.client.get(reverse('home'))
recent_hackathons = [hackathon.id for hackathon in response.context['recent_hackathons']]
upcoming_hackathons = [hackathon.id for hackathon in response.context['upcoming_hackathons']]
self.assertTrue(hackathon.id in recent_hackathons)
self.assertTrue(hackathon2.id in upcoming_hackathons)

self.client.force_login(self.super_user)
response = self.client.get(reverse('home'))
recent_hackathons = [hackathon.id for hackathon in response.context['recent_hackathons']]
upcoming_hackathons = [hackathon.id for hackathon in response.context['upcoming_hackathons']]
self.assertTrue(hackathon.id in recent_hackathons)
self.assertTrue(hackathon2.id in upcoming_hackathons)

hackathon.is_public = True
hackathon.save()
hackathon2.is_public = True
hackathon2.save()

self.client.force_login(self.user)
response = self.client.get(reverse('home'))
recent_hackathons = [hackathon.id for hackathon in response.context['recent_hackathons']]
upcoming_hackathons = [hackathon.id for hackathon in response.context['upcoming_hackathons']]
self.assertTrue(hackathon.id in recent_hackathons)
self.assertTrue(hackathon2.id in upcoming_hackathons)

hackathon.is_public = False
hackathon.save()
hackathon2.is_public = False
hackathon2.save()
self.user.organisation = self.partner_org
self.user.save()

self.client.force_login(self.user)
response = self.client.get(reverse('home'))
recent_hackathons = [hackathon.id for hackathon in response.context['recent_hackathons']]
upcoming_hackathons = [hackathon.id for hackathon in response.context['upcoming_hackathons']]
self.assertTrue(hackathon.id in recent_hackathons)
self.assertTrue(hackathon2.id in upcoming_hackathons)
Loading