Skip to content

Commit

Permalink
Merge branch 'dev' into position-postings
Browse files Browse the repository at this point in the history
  • Loading branch information
Muirrum authored Dec 13, 2021
2 parents d1906c8 + 75d9545 commit b596f59
Show file tree
Hide file tree
Showing 84 changed files with 4,646 additions and 1,053 deletions.
46 changes: 46 additions & 0 deletions .github/workflows/django-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: Django CI

on:
push:
branches: [ master, dev ]
pull_request:
branches: [ master, dev ]

jobs:
build:

runs-on: ubuntu-latest
strategy:
max-parallel: 4
matrix:
python-version: [3.6, 3.7]

steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install Dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements_debug.txt
- name: Run Tests
run: coverage run --omit="*/migrations/*","slack/api.py","inventory/*","src/*" manage.py test
- name: Upload Coverage
run: coveralls --service=github
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COVERALLS_FLAG_NAME: ${{ matrix.python-version }}
COVERALLS_PARALLEL: true
coveralls:
name: Indicate completion to coveralls.io
needs: build
runs-on: ubuntu-latest
steps:
- name: Finished
run: |
pip install --upgrade coveralls
coveralls --service=github --finish
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# LNLDB
[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) [![Build Status](https://travis-ci.org/WPI-LNL/lnldb.svg)](https://travis-ci.org/WPI-LNL/lnldb) [![Coverage Status](https://coveralls.io/repos/WPI-LNL/lnldb/badge.svg?branch=master&service=github)](https://coveralls.io/github/WPI-LNL/lnldb?branch=master) [![Documentation](https://readthedocs.org/projects/lnldb/badge/?version=latest&style=flat)](https://lnldb.readthedocs.io/en/latest/)
[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) [![Django CI](https://github.com/WPI-LNL/lnldb/actions/workflows/django-ci.yml/badge.svg)](https://github.com/WPI-LNL/lnldb/actions/workflows/django-ci.yml) [![Coverage Status](https://coveralls.io/repos/WPI-LNL/lnldb/badge.svg?branch=master&service=github)](https://coveralls.io/github/WPI-LNL/lnldb?branch=master) [![Documentation](https://readthedocs.org/projects/lnldb/badge/?version=latest&style=flat)](https://lnldb.readthedocs.io/en/latest/)

## Intro
LNLDB now runs under Python3.x and Django 2.2 or later.
Expand Down
161 changes: 156 additions & 5 deletions accounts/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from django import forms

from data.forms import FieldAccessForm, FieldAccessLevel
from .models import OfficerImg, carrier_choices
from .models import OfficerImg, carrier_choices, event_fields, UserPreferences
from .ldap import get_student_id


Expand Down Expand Up @@ -70,13 +70,12 @@ def __init__(self):

thisisme = FieldAccessLevel(
lambda user, instance: (user == instance) and not user.locked,
enable=('email', 'first_name', 'last_name', 'addr', 'wpibox',
'phone', 'class_year', 'nickname', 'carrier', 'pronouns')
enable=('email', 'first_name', 'last_name', 'addr', 'wpibox', 'phone', 'class_year', 'nickname', 'carrier',
'pronouns')
)
hasperm = FieldAccessLevel(
lambda user, instance: (user != instance) and user.has_perm('accounts.change_user', instance),
enable=('email', 'first_name', 'last_name', 'addr', 'wpibox',
'phone', 'class_year')
enable=('email', 'first_name', 'last_name', 'addr', 'wpibox', 'phone', 'class_year')
)
edit_groups = FieldAccessLevel(
lambda user, instance: user.has_perm('accounts.change_membership', instance),
Expand Down Expand Up @@ -153,6 +152,158 @@ def save(self, commit=True):
return user


class UserPreferencesForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(UserPreferencesForm, self).__init__(*args, **kwargs)
if self.instance.rt_token not in [None, '']:
self.Meta.layout.pop(-2)
self.Meta.layout.insert(-1, (
"Text", "<button class=\"ui red small button\" type=\"submit\" name=\"submit\" "
"value=\"rt-delete\">Delete Token</button>"
))
else:
self.Meta.layout.pop(-2)
self.Meta.layout.insert(-1, (
"Text", "<a href=\"/support/connect/rt/\" class=\"ui green small button\">Connect Account</a>"
))

if 'Inactive' in self.instance.user.group_str or 'Unclassified' in self.instance.user.group_str:
self.Meta.layout[8] = ("Text", "</div><div class=\"title\"><i class=\"dropdown icon\"></i>"
"Crew Chief Needed Notifications</div><div class=\"content\">"
"<p class=\"ui help\">Receive an alert whenever the VP needs crew chiefs "
"to run an event. These messages may be sent to either "
"<em>[email protected]</em> or <em>[email protected]</em>. You may "
"unsubscribe from these messages at any time through Outlook.</p>")
self.Meta.layout[9] = (
"Text", "<a href=\"https://lnl.wpi.edu/legal/opt-out/\" class=\"ui blue basic button\">Opt out</a>"
)
else:
self.Meta.layout[8] = ("Text", "</div><div class=\"title\"><i class=\"dropdown icon\"></i>"
"Crew Chief Needed Notifications</div><div class=\"content\">"
"<p class=\"ui help\">Receive an alert whenever the VP needs crew chiefs "
"to run an event.</p>")
self.Meta.layout[9] = ("Field", "cc_needed_subscriptions")
self.fields['cc_needed_subscriptions'].initial = ['email', 'slack']

event_fields_required = [
('location', 'Location'),
('datetime_setup_complete', 'Datetime setup complete'),
('datetime_start', 'Datetime start'),
('datetime_end', 'Datetime end')
]

event_fields_optional = []
for field in event_fields:
if field not in event_fields_required:
event_fields_optional.append(field)
self.fields['event_edited_field_subscriptions'].choices = event_fields_optional

self.fields['ignore_user_action'].widget.attrs['_style'] = 'toggle'
self.fields['ignore_user_action'].widget.attrs['_help'] = True

cc_add_subscriptions = forms.MultipleChoiceField(
choices=(('email', 'Email'), ('slack', 'Slack Notification')),
required=False,
widget=forms.CheckboxSelectMultiple(attrs={
'_no_required': True, 'style': 'margin: 0.5% 0.5% 0 0; cursor: pointer', '_no_label': True
})
)

cc_report_reminders = forms.ChoiceField(
choices=(('email', 'Email'), ('slack', 'Slack Notification'), ('all', 'Both')),
widget=forms.RadioSelect(attrs={
'_no_required': True, 'style': 'margin: 0.5% 0.5% 0 0; cursor: pointer', '_no_label': True
})
)

cc_needed_subscriptions = forms.MultipleChoiceField(
choices=(('email', 'Email'), ('slack', 'Slack Notification')),
required=False,
widget=forms.CheckboxSelectMultiple(
attrs={'_no_required': True, 'style': 'margin: 0.5% 0.5% 0 0; cursor: pointer', '_no_label': True, 'disabled': True}
)
)

event_edited_notification_methods = forms.ChoiceField(
choices=(('email', 'Email'), ('slack', 'Slack Notification'), ('all', 'Both')),
widget=forms.RadioSelect(attrs={
'_no_required': True, 'style': 'margin: 0.5% 0.5% 0 0; cursor: pointer', '_no_label': True
})
)

event_edited_field_subscriptions = forms.MultipleChoiceField(
choices=event_fields,
required=False,
widget=forms.SelectMultiple(attrs={'_no_required': True, '_no_label': True, 'placeholder': 'Add more'})
)

ignore_user_action = forms.BooleanField(label="Ignore my actions", required=False,
help_text="Avoid sending me notifications for actions that I initiate")

srv = forms.MultipleChoiceField(
choices=(('email', 'Email'), ('slack', 'Slack Notification'), ('sms', 'SMS (Text Message)')),
initial=['email', 'slack', 'sms'],
required=False,
widget=forms.CheckboxSelectMultiple(
attrs={'_no_required': True, 'style': 'margin: 0.5% 0.5% 0 0', '_no_label': True, 'disabled': True}
)
)

class Meta:
model = UserPreferences
fields = ('theme', 'cc_add_subscriptions', 'cc_report_reminders', 'event_edited_notification_methods',
'event_edited_field_subscriptions', 'ignore_user_action')
layout = [
("Text", "<div class=\"ui secondary segment\"><h4 class=\"ui dividing header\">Appearance</h4>"),
("Field", "theme"),

("Text", "</div><div class=\"ui secondary segment nobullet\"><h4 class=\"ui dividing header\">"
"Communications</h4><div class=\"ui styled accordion\" style=\"width: 100%\"><div class=\"title\">"
"<i class=\"dropdown icon\"></i>LNL News</div><div class=\"content\"><p class=\"ui help\">"
"General club information, advertisements and meeting notices. This content will typically be "
"sent to the <em>[email protected]</em> email alias. You may opt out of receiving these messages "
"at any time through Outlook.</p>"),
("Text", "<a href=\"https://lnl.wpi.edu/legal/opt-out/\" class=\"ui blue basic button\">Opt out</a>"),

("Text", "</div><div class=\"title\"><i class=\"dropdown icon\"></i>Crew Chief Add Notifications</div>"
"<div class=\"content\"><p class=\"ui help\">Receive a notification whenever you are added as a "
"Crew Chief for a new event.</p>"),
("Field", "cc_add_subscriptions"),

("Text", "</div><div class=\"title\"><i class=\"dropdown icon\"></i>Crew Chief Report Reminders</div>"
"<div class=\"content\"><p class=\"ui help\">Receive reminders for missing crew chief reports.</p>"),
("Field", "cc_report_reminders"),

("Text", "</div><div class=\"title\"><i class=\"dropdown icon\"></i>Crew Chief Needed Notifications</div>"
"<div class=\"content\"><p class=\"ui help\">Receive an alert whenever the VP needs crew chiefs "
"to run an event.</p>"),
("Field", "cc_needed_subscriptions"),

("Text", "</div><div class=\"title\"><i class=\"dropdown icon\"></i>Event Edit Notifications</div>"
"<div class=\"content\"><p class=\"ui help\">Receive alerts whenever details for an event you are "
"involved with have changed.</p>"),
("Field", "event_edited_notification_methods"),
("Text", "<br><hr style='border: 1px dashed gray'><br>"
"<p class\"ui help\">Notify me of changes to any of the following fields:<br><br>"
"<span class=\"ui label\">Location</span><span class=\"ui label\">Event Setup Time</span>"
"<span class=\"ui label\">Event Start</span><span class=\"ui label\">Event End</span></p>"),
("Field", "event_edited_field_subscriptions"),

("Text", "</div><div class=\"title\"><i class=\"dropdown icon\"></i>Web Service Notifications</div>"
"<div class=\"content\"><p class=\"ui help\">General account and system-wide notices. You may not "
"unsubscribe from these messages.</p>"),
("Field", "srv"),

("Text", "</div></div><div class=\"ui segment\">"),
("Field", "ignore_user_action"),

("Text", "</div></div><div class=\"ui secondary segment\">"
"<h4 class=\"ui dividing header\">Request Tracker</h4>"),
("Text", "<a href=\"/support/connect/rt/\" class=\"ui green basic button\">Connect Account</a>"),
("Text", "</div>")
]


class OfficerPhotoForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.helper = FormHelper()
Expand Down
39 changes: 39 additions & 0 deletions accounts/migrations/0007_comm_prefs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Generated by Django 3.1.8 on 2021-11-21 19:19

from django.db import migrations, models
import multiselectfield.db.fields


class Migration(migrations.Migration):

dependencies = [
('accounts', '0006_user_pronouns'),
]

operations = [
migrations.AddField(
model_name='userpreferences',
name='cc_add_subscriptions',
field=multiselectfield.db.fields.MultiSelectField(blank=True, choices=[('email', 'Email'), ('slack', 'Slack Notification')], default='email', max_length=11, null=True),
),
migrations.AddField(
model_name='userpreferences',
name='cc_report_reminders',
field=models.CharField(choices=[('email', 'Email'), ('slack', 'Slack Notification'), ('all', 'Both')], default='email', max_length=12),
),
migrations.AddField(
model_name='userpreferences',
name='event_edited_field_subscriptions',
field=multiselectfield.db.fields.MultiSelectField(choices=[('event_name', 'Event name'), ('description', 'Description'), ('location', 'Location'), ('contact', 'Contact'), ('billing_org', 'Billing org'), ('datetime_setup_complete', 'Datetime setup complete'), ('datetime_start', 'Datetime start'), ('datetime_end', 'Datetime end'), ('internal_notes', 'Internal notes'), ('billed_in_bulk', 'Billed in bulk'), ('org', 'Client')], default=['location', 'datetime_setup_complete', 'datetime_start', 'datetime_end'], max_length=137),
),
migrations.AddField(
model_name='userpreferences',
name='event_edited_notification_methods',
field=models.CharField(choices=[('email', 'Email'), ('slack', 'Slack Notification'), ('all', 'Both')], default='email', max_length=12),
),
migrations.AddField(
model_name='userpreferences',
name='ignore_user_action',
field=models.BooleanField(default=False, help_text='Uncheck this to ignore notifications for actions triggered by the user'),
),
]
38 changes: 38 additions & 0 deletions accounts/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from django.contrib.auth.models import AbstractUser, _user_has_perm
from django.db.models import (Model, BooleanField, CharField, IntegerField, BigIntegerField, PositiveIntegerField, Q,
TextField, DateField, DateTimeField, OneToOneField, ImageField, CASCADE, signals)
from multiselectfield import MultiSelectField
from django.conf import settings
from six import python_2_unicode_compatible
from django.dispatch import receiver
Expand Down Expand Up @@ -209,9 +210,46 @@ class PhoneVerificationCode(Model):
timestamp = DateTimeField(auto_now_add=True)


event_fields = [
('event_name', 'Event name'),
('description', 'Description'),
('location', 'Location'),
('contact', 'Contact'),
('billing_org', 'Billing org'),
('datetime_setup_complete', 'Datetime setup complete'),
('datetime_start', 'Datetime start'),
('datetime_end', 'Datetime end'),
('internal_notes', 'Internal notes'),
('billed_in_bulk', 'Billed in bulk'),
('org', 'Client')
]


class UserPreferences(Model):
""" User-specific settings """
user = OneToOneField(settings.AUTH_USER_MODEL, on_delete=CASCADE, related_name="preferences")
theme = CharField(choices=(("default", "Default"),), default="default", max_length=12)

rt_token = CharField(blank=True, null=True, verbose_name="RT Auth Token", max_length=256)

# Communication Preferences
cc_add_subscriptions = MultiSelectField(choices=(('email', 'Email'), ('slack', 'Slack Notification')),
default='email', blank=True, null=True)

cc_report_reminders = CharField(choices=(('email', 'Email'), ('slack', 'Slack Notification'), ('all', 'Both')),
default='email', max_length=12)

event_edited_notification_methods = CharField(
choices=(('email', 'Email'), ('slack', 'Slack Notification'), ('all', 'Both')),
default='email',
max_length=12
)

event_edited_field_subscriptions = MultiSelectField(
choices=event_fields,
default=['location', 'datetime_setup_complete', 'datetime_start', 'datetime_end']
)

ignore_user_action = BooleanField(
default=False, help_text="Uncheck this to ignore notifications for actions triggered by the user"
)
15 changes: 7 additions & 8 deletions accounts/perms.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,20 @@


class EventUserPermLogic(AssocUsersCustomPermissionLogic):
field_name = ['submitter__contact', 'submiter_crew_chief', 'submitter__ccinstances__crew_chief',
field_name = ['submitter__contact', 'submitter__crew_chief', 'submitter__ccinstances__crew_chief',
'event__submitted_by', 'event__crew_chief', 'event__ccinstances__crew_chief',
'ccinstances__event__submitted_by', 'ccinstances__event__contact',
'ccinstances__event_crew_chief',
'crewchiefx__contact', 'crewchiefx__submitted_by',
'crewchiefx__ccinstances__crew_chief']
perms = ('accounts.read_user',)
'ccinstances__event__submitted_by', 'ccinstances__event__contact', 'ccinstances__event__crew_chief',
'crewchiefx__contact', 'crewchiefx__submitted_by', 'crewchiefx__ccinstances__crew_chief',
'contact__ccinstances__crew_chief', 'contact__crew_chief', 'contact__submitted_by']
perms = ('accounts.view_user',)


# Begin Intra-Org

class IntraOrgPermLogic(AssocUsersCustomPermissionLogic):
field_name = ['orgusers__associated_users', 'orgowner__associated_users',
'orgusers__user_in_charge']
perms = ('accounts.read_user',)
perms = ('accounts.view_user',)


# will only go one level. And that's a good thing.
Expand All @@ -25,7 +24,7 @@ class AssocOrgPermLogic(AssocUsersCustomPermissionLogic):
'orgowner__associated_orgs__associated_users',
'orgusers__associated_orgs__user_in_charge',
'orgowner__associated_orgs__user_in_charge']
perms = ('accounts.read_user',)
perms = ('accounts.view_user',)


PERMISSION_LOGICS = (
Expand Down
Loading

0 comments on commit b596f59

Please sign in to comment.