From dee3c68d40c4ba87e568f7723cd4b8a3cfc6f0a4 Mon Sep 17 00:00:00 2001 From: Benjamin A Date: Thu, 2 Jan 2025 23:00:49 -0800 Subject: [PATCH] Move channels for groups to channel model update details and list --- accounts/lookups.py | 20 ++++++++ lnldb/settings.py | 1 + site_tmpl/slack/slack_channel_detail.html | 46 +++++++++++++++++-- site_tmpl/slack/slack_channel_list.html | 12 ++++- ..._allowed_groups_channel_required_groups.py | 32 +++++++++++++ ...6_alter_channel_allowed_groups_and_more.py | 33 +++++++++++++ slack/models.py | 13 ++++++ slack/urls.py | 1 + slack/views.py | 26 +++++++++-- 9 files changed, 173 insertions(+), 11 deletions(-) create mode 100644 slack/migrations/0005_channel_allowed_groups_channel_required_groups.py create mode 100644 slack/migrations/0006_alter_channel_allowed_groups_and_more.py diff --git a/accounts/lookups.py b/accounts/lookups.py index c92703fb..32622a40 100644 --- a/accounts/lookups.py +++ b/accounts/lookups.py @@ -1,6 +1,7 @@ from ajax_select import LookupChannel from django.contrib.auth import get_user_model from django.db.models import Q +from django.contrib.auth.models import Group from . import ldap from . import graph @@ -37,6 +38,25 @@ def format_item_display(self, obj): (self.get_result(obj), ", ".join(map(str, obj.groups.all()))) return ' %s' % self.get_result(obj) +class GroupLookup(LookupChannel): + model = Group + + def check_auth(self, request): + if request.user.groups.filter(Q(name="Alumni") | Q(name="Active") | Q(name="Officer")).exists(): + return True + + def get_query(self, q, request, search_ldap=True): + qs = Q() + for term in q.split(): + qs &= Q(name__icontains=term) + return Group.objects.filter(qs).distinct().all() + + def format_match(self, obj): + return self.format_item_display(obj) + + def format_item_display(self, obj): + return ' %s (%s users)' % \ + (self.get_result(obj), obj.user_set.count()) class OfficerLookup(LookupChannel): model = get_user_model() diff --git a/lnldb/settings.py b/lnldb/settings.py index 29e5ebad..d395700c 100644 --- a/lnldb/settings.py +++ b/lnldb/settings.py @@ -444,6 +444,7 @@ def from_runtime(*x): AJAX_LOOKUP_CHANNELS = { 'Users': ('accounts.lookups', 'UserLookup'), + 'Groups': ('accounts.lookups', 'GroupLookup'), 'Orgs': ('events.lookups', 'OrgLookup'), 'UserLimitedOrgs': ('events.lookups', 'UserLimitedOrgLookup'), 'Officers': ('accounts.lookups', 'OfficerLookup'), diff --git a/site_tmpl/slack/slack_channel_detail.html b/site_tmpl/slack/slack_channel_detail.html index 4185c789..e88d3094 100644 --- a/site_tmpl/slack/slack_channel_detail.html +++ b/site_tmpl/slack/slack_channel_detail.html @@ -15,7 +15,7 @@

Last Updated: {{ channel.last_updated }}

Open in Slack - + @@ -24,17 +24,53 @@

Last Updated: {{ channel.last_updated }}

-

Channel Configuration

+

Channel Configuration + {% if form == None %} + Edit Groups + {% endif %} +

+{% if form %} +
+{% csrf_token %} +{{ form.media }} +{% endif %} - + - +
Groups Allowed{{ channel.groups_allowed }} + {% if form %} + {{ form.allowed_groups }} + {% for error in form.username.errors %} + {{error}} + {% endfor %} + {% else %} + {% for group in channel.allowed_groups.all %} + {{ group.name }} + {% endfor %} + {% endif %} +
Groups Required{{ channel.groups_required }} + {% if form %} + {{ form.required_groups }} + {% for error in form.username.errors %} + {{error}} + {% endfor %} + + {% else %} + {% for group in channel.required_groups.all %} + {{ group.name }} + {% endfor %} + {% endif %} +
+ {% if form %} + +
+ {% endif %}

Channel Details

@@ -55,7 +91,7 @@

Channel Details

- + diff --git a/site_tmpl/slack/slack_channel_list.html b/site_tmpl/slack/slack_channel_list.html index 232d5417..324e2cc5 100644 --- a/site_tmpl/slack/slack_channel_list.html +++ b/site_tmpl/slack/slack_channel_list.html @@ -20,8 +20,16 @@

{{ h2 }}

- - + + {% endfor %}
Created by{% if creator_name %}{{ creator_name }}{% endif %}{% if channel.creator %}{{ channel.creator.get_full_name }}{% endif %}
Created on {{ channel.num_members }} {{ channel.last_updated }}{{ channel.groups_allowed }}{{ channel.groups_required }} + {% for group in channel.allowed_groups.all %} + {{ group.name }} + {% endfor %} + + {% for group in channel.required_groups.all %} + {{ group.name }} + {% endfor %} +
diff --git a/slack/migrations/0005_channel_allowed_groups_channel_required_groups.py b/slack/migrations/0005_channel_allowed_groups_channel_required_groups.py new file mode 100644 index 00000000..26b9120b --- /dev/null +++ b/slack/migrations/0005_channel_allowed_groups_channel_required_groups.py @@ -0,0 +1,32 @@ +# Generated by Django 4.2.13 on 2025-01-03 06:15 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("slack", "0004_remove_channel_channel_id_alter_channel_id"), + ] + + operations = [ + migrations.AddField( + model_name="channel", + name="allowed_groups", + field=models.ManyToManyField( + blank=True, + related_name="allowed_channels", + to="slack.channel", + verbose_name="Allowed Groups", + ), + ), + migrations.AddField( + model_name="channel", + name="required_groups", + field=models.ManyToManyField( + blank=True, + related_name="required_channels", + to="slack.channel", + verbose_name="Required Groups", + ), + ), + ] diff --git a/slack/migrations/0006_alter_channel_allowed_groups_and_more.py b/slack/migrations/0006_alter_channel_allowed_groups_and_more.py new file mode 100644 index 00000000..b71cee42 --- /dev/null +++ b/slack/migrations/0006_alter_channel_allowed_groups_and_more.py @@ -0,0 +1,33 @@ +# Generated by Django 4.2.13 on 2025-01-03 06:18 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("auth", "0014_remove_group_allowed_channels_and_more"), + ("slack", "0005_channel_allowed_groups_channel_required_groups"), + ] + + operations = [ + migrations.AlterField( + model_name="channel", + name="allowed_groups", + field=models.ManyToManyField( + blank=True, + related_name="allowed_channels", + to="auth.group", + verbose_name="Allowed Groups", + ), + ), + migrations.AlterField( + model_name="channel", + name="required_groups", + field=models.ManyToManyField( + blank=True, + related_name="required_channels", + to="auth.group", + verbose_name="Required Groups", + ), + ), + ] diff --git a/slack/models.py b/slack/models.py index d22f6429..e55408b6 100755 --- a/slack/models.py +++ b/slack/models.py @@ -1,6 +1,7 @@ import datetime from django.db import models from django.contrib.auth import get_user_model +from django.contrib.auth.models import Group from .api import channel_info, channel_members, channel_latest_message, user_profile @@ -42,6 +43,18 @@ class Channel(models.Model): Used to store Slack channel ID and retrieve common information about Slack channels """ id = models.CharField(max_length=256, unique=True, primary_key=True) + allowed_groups = models.ManyToManyField( + Group, + verbose_name="Allowed Groups", + related_name="allowed_channels", + blank=True, + ) + required_groups = models.ManyToManyField( + Group, + verbose_name="Required Groups", + related_name="required_channels", + blank=True, + ) def __str__(self): return self.name diff --git a/slack/urls.py b/slack/urls.py index 42e3c38d..73259527 100644 --- a/slack/urls.py +++ b/slack/urls.py @@ -12,5 +12,6 @@ re_path(r'^moderate/$', views.report_list, name="moderate"), re_path(r'^moderate/(?P\d+)/$', views.view_report, name="report"), re_path(r'^channels/$', views.channel_list, name="channel-list"), + re_path(r'^channel/(?P[^/]+)/edit/$', views.channel_detail_edit, name="channel-edit"), re_path(r'^channel/(?P[^/]+)/$', views.channel_detail, name="channel"), ] diff --git a/slack/views.py b/slack/views.py index 6f18227c..5f77e8eb 100644 --- a/slack/views.py +++ b/slack/views.py @@ -1,3 +1,5 @@ +from ajax_select.fields import AutoCompleteSelectMultipleField +from django import forms from django.contrib.auth.decorators import permission_required, login_required from django.shortcuts import reverse, render, get_object_or_404 from django.http import HttpResponseRedirect @@ -22,20 +24,36 @@ def channel_list(request): 'channels': channels, 'slack_base_url': settings.SLACK_BASE_URL+'/archives/'}) +class ChannelAssignGroupForm(forms.ModelForm): + allowed_groups = AutoCompleteSelectMultipleField('Groups', required=False) + required_groups = AutoCompleteSelectMultipleField('Groups', required=False) + class Meta: + model = Channel + fields = ('allowed_groups', 'required_groups') + @login_required @permission_required('slack.view_channel', raise_exception=True) -def channel_detail(request, id): +def channel_detail_edit(request, id): + return channel_detail(request, id, edit=True) + +@login_required +@permission_required('slack.view_channel', raise_exception=True) +def channel_detail(request, id, edit=False): """ View details for a specific Slack channel """ channel = get_object_or_404(Channel, id=id) + if request.method == 'POST': + form = ChannelAssignGroupForm(data=request.POST, instance=channel) + if form.is_valid(): + form.save(commit=True) + return HttpResponseRedirect(reverse('slack:channel', args=[id])) return render(request, 'slack/slack_channel_detail.html', {'h2': "#"+channel.name+' Details', 'channel': channel, - 'creator_name': channel.creator.get_full_name() if channel.creator else None, + #'creator_name': channel.creator.get_full_name() if channel.creator else None, 'slack_base_url': settings.SLACK_BASE_URL+'/archives/', - 'groups_allowed': channel.allowed_groups.all(), # TODO: Fix implementation - 'groups_required': channel.required_groups.all()}) # TODO: Fix implementation + 'form': ChannelAssignGroupForm(instance=channel) if edit else None})