Skip to content

Commit

Permalink
Merge pull request #549 from uw-it-aca/work/google-shared-drives-mikes
Browse files Browse the repository at this point in the history
Work/google shared drives mikes
  • Loading branch information
mikeseibel authored May 8, 2024
2 parents 74c8d5e + d4d5a11 commit e9dbd64
Show file tree
Hide file tree
Showing 24 changed files with 900 additions and 231 deletions.
7 changes: 7 additions & 0 deletions endorsement/dao/shared_drive.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@
r'^(?P<netid>[^@]+)@(uw|(u\.)?washington)\.edu$', re.I)


def shared_drive_lifecycle_expired(drive_record):
"""
Set lifecycle to expired for shared drive
"""
logger.info(f"Shared drive {drive_record} lifecycle expired")


def load_shared_drives_from_csv(file_path):
"""
populate shared drive models
Expand Down
22 changes: 11 additions & 11 deletions endorsement/fixtures/test_data/member.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,54 +2,54 @@
"model": "endorsement.member",
"pk": 1,
"fields": {
"name": "javerage"}},
"netid": "javerage"}},
{
"model": "endorsement.member",
"pk": 2,
"fields": {
"name": "endorsee7"}},
"netid": "endorsee7"}},
{
"model": "endorsement.member",
"pk": 3,
"fields": {
"name": "[email protected]"}},
"netid": "[email protected]"}},
{
"model": "endorsement.member",
"pk": 4,
"fields": {
"name": "endorsee6"}},
"netid": "endorsee6"}},
{
"model": "endorsement.member",
"pk": 5,
"fields": {
"name": "jstaff"}},
"netid": "jstaff"}},
{
"model": "endorsement.member",
"pk": 6,
"fields": {
"name": "jinter"}},
"netid": "jinter"}},
{
"model": "endorsement.member",
"pk": 7,
"fields": {
"name": "endorsee5"}},
"netid": "endorsee5"}},
{
"model": "endorsement.member",
"pk": 8,
"fields": {
"name": "endorsee4"}},
"netid": "endorsee4"}},
{
"model": "endorsement.member",
"pk": 9,
"fields": {
"name": "endorsee3"}},
"netid": "endorsee3"}},
{
"model": "endorsement.member",
"pk": 10,
"fields": {
"name": "endorsee2"}},
"netid": "endorsee2"}},
{
"model": "endorsement.member",
"pk": 11,
"fields": {
"name": "endorsee1"}}]
"netid": "endorsee1"}}]
2 changes: 1 addition & 1 deletion endorsement/management/commands/expire_endorsees.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from django.core.management.base import BaseCommand
from django.core.mail import mail_managers
from django.template import loader
from endorsement.policy import endorsements_to_expire
from endorsement.policy.endorsement import endorsements_to_expire
from endorsement.dao.endorse import clear_endorsement
import logging
import urllib3
Expand Down
23 changes: 23 additions & 0 deletions endorsement/migrations/0028_auto_20240506_1259.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 3.2.25 on 2024-05-06 19:59

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('endorsement', '0027_auto_20240503_1436'),
]

operations = [
migrations.RenameField(
model_name='member',
old_name='name',
new_name='netid',
),
migrations.AlterField(
model_name='shareddrive',
name='members',
field=models.ManyToManyField(blank=True, to='endorsement.SharedDriveMember'),
),
]
20 changes: 20 additions & 0 deletions endorsement/migrations/0029_auto_20240508_1240.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Django 3.2.25 on 2024-05-08 19:40

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('endorsement', '0028_auto_20240506_1259'),
]

operations = [
migrations.RemoveField(
model_name='shareddriverecord',
name='acceptance',
),
migrations.DeleteModel(
name='SharedDriveAcceptance',
),
]
26 changes: 26 additions & 0 deletions endorsement/migrations/0030_shareddriveacceptance.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Generated by Django 3.2.25 on 2024-05-08 19:42

from django.db import migrations, models
import django.db.models.deletion
import django_prometheus.models


class Migration(migrations.Migration):

dependencies = [
('endorsement', '0029_auto_20240508_1240'),
]

operations = [
migrations.CreateModel(
name='SharedDriveAcceptance',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('action', models.SmallIntegerField(choices=[(0, 'Accept'), (1, 'Revoke')], default=0)),
('datetime_accepted', models.DateTimeField(auto_now_add=True)),
('member', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='endorsement.member')),
('shared_drive_record', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='endorsement.shareddriverecord')),
],
bases=(django_prometheus.models.ExportModelOperationsMixin('shared_drive_acceptance'), models.Model),
),
]
102 changes: 60 additions & 42 deletions endorsement/models/shared_drive.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,19 @@


class MemberManager(models.Manager):
def get_member(self, name):
member, _ = self.get_or_create(name=name)
def get_member(self, netid):
member, _ = self.get_or_create(netid=netid)
return member


class Member(ExportModelOperationsMixin('member'), models.Model):
"""
Member represents user associated with a shared drive
"""
name = models.CharField(max_length=128)
netid = models.CharField(max_length=128)

def json_data(self):
return self.name
return self.netid

objects = MemberManager()

Expand Down Expand Up @@ -52,7 +52,7 @@ class SharedDriveMember(

def json_data(self):
return {
"name": self.member.json_data(),
"netid": self.member.json_data(),
"role": self.role.json_data()
}

Expand Down Expand Up @@ -84,6 +84,9 @@ def json_data(self):
"is_subsidized": self.is_subsidized
}

def __str__(self):
return json.dumps(self.json_data())


class SharedDrive(ExportModelOperationsMixin('shared_drive'), models.Model):
"""
Expand All @@ -94,9 +97,12 @@ class SharedDrive(ExportModelOperationsMixin('shared_drive'), models.Model):
drive_name = models.CharField(max_length=128)
drive_quota = models.ForeignKey(SharedDriveQuota, on_delete=models.PROTECT)
drive_usage = models.IntegerField(null=True)
members = models.ManyToManyField(SharedDriveMember)
members = models.ManyToManyField(SharedDriveMember, blank=True)
query_date = models.DateTimeField(null=True)

def get_members(self):
return [m.member.netid for m in self.members.all()]

def json_data(self):
return {
"drive_id": self.drive_id,
Expand All @@ -108,41 +114,10 @@ def json_data(self):

def __str__(self):
return json.dumps(self.json_data())


class SharedDriveAcceptance(
ExportModelOperationsMixin('shared_drive_acceptance'), models.Model):
"""
SharedDriveAcceptance model records each instance of a shared drive
record being accepted or revoked by a shared drive manager.
"""
ACCEPT = 0
REVOKE = 1

ACCEPTANCE_ACTION_CHOICES = (
(ACCEPT, "Accept"),
(REVOKE, "Revoke"))

member = models.ForeignKey(Member, on_delete=models.PROTECT)
action = models.SmallIntegerField(
default=ACCEPT, choices=ACCEPTANCE_ACTION_CHOICES)
datetime_accepted = models.DateTimeField(auto_now_add=True)

def json_data(self):
return {
"member": self.member.json_data(),
"action": self.ACCEPTANCE_ACTION_CHOICES[self.action][1],
"datetime_accepted": datetime_to_str(self.datetime_accepted)
}

def __str__(self):
return json.dumps(self.json_data())


class SharedDriveRecordManager(models.Manager):
def get_member_drives(self, member_netid, drive_id=None):
parms = {
"shared_drive__members__member__name": member_netid,
"shared_drive__members__member__netid": member_netid,
"is_deleted__isnull": True}

if drive_id:
Expand Down Expand Up @@ -177,7 +152,6 @@ class SharedDriveRecord(
datetime_notice_4_emailed = models.DateTimeField(null=True)
datetime_renewed = models.DateTimeField(null=True)
datetime_expired = models.DateTimeField(null=True)
acceptance = models.ManyToManyField(SharedDriveAcceptance, blank=True)
is_deleted = models.BooleanField(null=True)

objects = SharedDriveRecordManager()
Expand All @@ -204,20 +178,31 @@ def itbill_form_url(self):
f"&remote_key={self.subscription.key_remote}"
f"&shared_drive={self.shared_drive.drive_name}")

@property
def acceptor(self):
if not self.datetime_accepted:
return None

return SharedDriveAcceptance.objects.get(
shared_drive_record=self,
datetime_accepted=self.datetime_accepted)

def get_acceptance(self):
return SharedDriveAcceptance.objects.filter(
shared_drive_record=self)

def set_acceptance(self, member_netid, accept=True):
member = Member.objects.get_member(member_netid)
action = SharedDriveAcceptance.ACCEPT if (
accept) else SharedDriveAcceptance.REVOKE

acceptance = SharedDriveAcceptance.objects.create(
member=member, action=action)
self.acceptance.add(acceptance)
shared_drive_record=self, member=member, action=action)

if accept:
self.datetime_accepted = acceptance.datetime_accepted
else:
self.datetime_expired = acceptance.datetime_accepted
self.is_deleted = True

self.save()

Expand Down Expand Up @@ -245,6 +230,7 @@ def json_data(self):
"datetime_notice_4_emailed": datetime_to_str(
self.datetime_notice_4_emailed),
"datetime_accepted": datetime_to_str(self.datetime_accepted),
"acceptance": [a.json_data() for a in self.get_acceptance()],
"datetime_renewed": datetime_to_str(self.datetime_renewed),
"datetime_expired": datetime_to_str(self.datetime_expired),
"datetime_expiration": datetime_to_str(self.expiration_date),
Expand All @@ -253,3 +239,35 @@ def json_data(self):

def __str__(self):
return json.dumps(self.json_data())


class SharedDriveAcceptance(
ExportModelOperationsMixin('shared_drive_acceptance'), models.Model):
"""
SharedDriveAcceptance model records each instance of a shared drive
record being accepted or revoked by a shared drive manager.
"""
ACCEPT = 0
REVOKE = 1

ACCEPTANCE_ACTION_CHOICES = (
(ACCEPT, "Accept"),
(REVOKE, "Revoke"))

shared_drive_record = models.ForeignKey(
SharedDriveRecord, on_delete=models.PROTECT)
member = models.ForeignKey(
Member, on_delete=models.PROTECT)
action = models.SmallIntegerField(
default=ACCEPT, choices=ACCEPTANCE_ACTION_CHOICES)
datetime_accepted = models.DateTimeField(auto_now_add=True)

def json_data(self):
return {
"member": self.member.json_data(),
"action": self.ACCEPTANCE_ACTION_CHOICES[self.action][1],
"datetime_accepted": datetime_to_str(self.datetime_accepted)
}

def __str__(self):
return json.dumps(self.json_data())
1 change: 1 addition & 0 deletions endorsement/notifications/access.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from endorsement.models import AccessRecord
from endorsement.dao.notification import send_notification
from endorsement.dao.accessors import get_accessor_email
from endorsement.exceptions import EmailFailureException
from django.template import loader, Template, Context
import logging

Expand Down
3 changes: 2 additions & 1 deletion endorsement/notifications/endorsement.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@
from endorsement.dao.user import get_endorsee_email_model
from endorsement.dao import display_datetime
from endorsement.dao.endorse import clear_endorsement
from endorsement.policy import endorsements_to_warn
from endorsement.policy.endorsement import endorsements_to_warn
from endorsement.util.email import uw_email_address
from endorsement.util.string import listed_list
from endorsement.exceptions import EmailFailureException
from django.template import loader, Template, Context
from django.utils import timezone
import re
Expand Down
Loading

0 comments on commit e9dbd64

Please sign in to comment.