diff options
author | Gergely Csatari <gergely.csatari@nokia.com> | 2023-10-26 10:33:28 +0300 |
---|---|---|
committer | Gergely Csatari <gergely.csatari@nokia.com> | 2023-10-26 10:34:28 +0300 |
commit | 2ec0d7b9f5c1354977b821c6b06c24a3ffa13142 (patch) | |
tree | 6e449d92ddfc880ed007e9d8a8f25bda8fc7cb0f /src/account | |
parent | 0d3dd290aa6e7f39e7b0b3cbe448b6622f924240 (diff) |
that the development continues in GitHub
Change-Id: I25c58a679dbf92b2367d826429b7cda936bf9f0e
Signed-off-by: Gergely Csatari <gergely.csatari@nokia.com>
Diffstat (limited to 'src/account')
-rw-r--r-- | src/account/__init__.py | 8 | ||||
-rw-r--r-- | src/account/admin.py | 19 | ||||
-rw-r--r-- | src/account/apps.py | 15 | ||||
-rw-r--r-- | src/account/forms.py | 29 | ||||
-rw-r--r-- | src/account/middleware.py | 35 | ||||
-rw-r--r-- | src/account/migrations/0001_initial.py | 65 | ||||
-rw-r--r-- | src/account/migrations/0002_lab_description.py | 19 | ||||
-rw-r--r-- | src/account/migrations/0003_publicnetwork.py | 25 | ||||
-rw-r--r-- | src/account/migrations/0004_downtime.py | 24 | ||||
-rw-r--r-- | src/account/migrations/0005_auto_20200723_2100.py | 23 | ||||
-rw-r--r-- | src/account/migrations/0006_auto_20201109_1947.py | 23 | ||||
-rw-r--r-- | src/account/migrations/0007_userprofile_pulic_user.py | 18 | ||||
-rw-r--r-- | src/account/migrations/0008_auto_20210324_2106.py | 18 | ||||
-rw-r--r-- | src/account/migrations/0009_auto_20210324_2107.py | 18 | ||||
-rw-r--r-- | src/account/migrations/__init__.py | 0 | ||||
-rw-r--r-- | src/account/models.py | 297 | ||||
-rw-r--r-- | src/account/tests/__init__.py | 8 | ||||
-rw-r--r-- | src/account/tests/test_general.py | 60 | ||||
-rw-r--r-- | src/account/urls.py | 59 | ||||
-rw-r--r-- | src/account/views.py | 226 |
20 files changed, 0 insertions, 989 deletions
diff --git a/src/account/__init__.py b/src/account/__init__.py deleted file mode 100644 index b6fef6c..0000000 --- a/src/account/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -############################################################################## -# Copyright (c) 2016 Max Breitenfeldt and others. -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -############################################################################## diff --git a/src/account/admin.py b/src/account/admin.py deleted file mode 100644 index b4c142c..0000000 --- a/src/account/admin.py +++ /dev/null @@ -1,19 +0,0 @@ -############################################################################## -# Copyright (c) 2016 Max Breitenfeldt and others. -# Copyright (c) 2018 Parker Berberian, Sawyer Bergeron, and others. -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -############################################################################## - - -from django.contrib import admin - -from account.models import UserProfile, Lab, VlanManager, PublicNetwork - -admin.site.register(UserProfile) -admin.site.register(Lab) -admin.site.register(VlanManager) -admin.site.register(PublicNetwork) diff --git a/src/account/apps.py b/src/account/apps.py deleted file mode 100644 index 9814648..0000000 --- a/src/account/apps.py +++ /dev/null @@ -1,15 +0,0 @@ -############################################################################## -# Copyright (c) 2016 Max Breitenfeldt and others. -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -############################################################################## - - -from django.apps import AppConfig - - -class AccountsConfig(AppConfig): - name = 'account' diff --git a/src/account/forms.py b/src/account/forms.py deleted file mode 100644 index 28cb27d..0000000 --- a/src/account/forms.py +++ /dev/null @@ -1,29 +0,0 @@ -############################################################################## -# Copyright (c) 2016 Max Breitenfeldt and others. -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -############################################################################## - - -import django.forms as forms -import pytz as pytz -from django.utils.translation import gettext_lazy as _ - -from account.models import UserProfile - - -class AccountSettingsForm(forms.ModelForm): - class Meta: - model = UserProfile - fields = ['company', 'email_addr', 'public_user', 'ssh_public_key', 'pgp_public_key', 'timezone'] - labels = { - 'email_addr': _('Email Address'), - 'ssh_public_key': _('SSH Public Key'), - 'pgp_public_key': _('PGP Public Key'), - 'public_user': _('Public User') - } - - timezone = forms.ChoiceField(choices=[(x, x) for x in pytz.common_timezones], initial='UTC') diff --git a/src/account/middleware.py b/src/account/middleware.py deleted file mode 100644 index 6a46dfe..0000000 --- a/src/account/middleware.py +++ /dev/null @@ -1,35 +0,0 @@ -############################################################################## -# Copyright (c) 2016 Max Breitenfeldt and others. -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -############################################################################## - - -from django.utils import timezone -from django.utils.deprecation import MiddlewareMixin - -from account.models import UserProfile - - -class TimezoneMiddleware(MiddlewareMixin): - """ - Manage user's Timezone preference. - - Activate the timezone from request.user.userprofile if user is authenticated, - deactivate the timezone otherwise and use default (UTC) - """ - - def process_request(self, request): - if request.user.is_authenticated: - try: - tz = request.user.userprofile.timezone - timezone.activate(tz) - except UserProfile.DoesNotExist: - UserProfile.objects.create(user=request.user) - tz = request.user.userprofile.timezone - timezone.activate(tz) - else: - timezone.deactivate() diff --git a/src/account/migrations/0001_initial.py b/src/account/migrations/0001_initial.py deleted file mode 100644 index c8b5bdc..0000000 --- a/src/account/migrations/0001_initial.py +++ /dev/null @@ -1,65 +0,0 @@ -# Generated by Django 2.1 on 2018-09-14 14:48 - -import account.models -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.CreateModel( - name='Lab', - fields=[ - ('name', models.CharField(max_length=200, primary_key=True, serialize=False, unique=True)), - ('contact_email', models.EmailField(blank=True, max_length=200, null=True)), - ('contact_phone', models.CharField(blank=True, max_length=20, null=True)), - ('status', models.IntegerField(default=0)), - ('location', models.TextField(default='unknown')), - ('api_token', models.CharField(max_length=50)), - ('lab_user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), - ], - ), - migrations.CreateModel( - name='UserProfile', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('timezone', models.CharField(default='UTC', max_length=100)), - ('ssh_public_key', models.FileField(blank=True, null=True, upload_to=account.models.upload_to)), - ('pgp_public_key', models.FileField(blank=True, null=True, upload_to=account.models.upload_to)), - ('email_addr', models.CharField(default='email@mail.com', max_length=300)), - ('company', models.CharField(max_length=200)), - ('oauth_token', models.CharField(max_length=1024)), - ('oauth_secret', models.CharField(max_length=1024)), - ('jira_url', models.CharField(default='', max_length=100)), - ('full_name', models.CharField(default='', max_length=100)), - ('booking_privledge', models.BooleanField(default=False)), - ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), - ], - options={ - 'db_table': 'user_profile', - }, - ), - migrations.CreateModel( - name='VlanManager', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('vlans', models.TextField()), - ('block_size', models.IntegerField()), - ('allow_overlapping', models.BooleanField()), - ('reserved_vlans', models.TextField()), - ], - ), - migrations.AddField( - model_name='lab', - name='vlan_manager', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='account.VlanManager'), - ), - ] diff --git a/src/account/migrations/0002_lab_description.py b/src/account/migrations/0002_lab_description.py deleted file mode 100644 index 445501a..0000000 --- a/src/account/migrations/0002_lab_description.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 2.1 on 2018-09-14 20:22 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('account', '0001_initial'), - ] - - operations = [ - migrations.AddField( - model_name='lab', - name='description', - field=models.CharField(default='Lab description default', max_length=240), - preserve_default=False, - ), - ] diff --git a/src/account/migrations/0003_publicnetwork.py b/src/account/migrations/0003_publicnetwork.py deleted file mode 100644 index 71e5caa..0000000 --- a/src/account/migrations/0003_publicnetwork.py +++ /dev/null @@ -1,25 +0,0 @@ -# Generated by Django 2.1 on 2018-09-26 14:41 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('account', '0002_lab_description'), - ] - - operations = [ - migrations.CreateModel( - name='PublicNetwork', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('vlan', models.IntegerField()), - ('in_use', models.BooleanField(default=False)), - ('cidr', models.CharField(default='0.0.0.0/0', max_length=50)), - ('gateway', models.CharField(default='0.0.0.0', max_length=50)), - ('lab', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='account.Lab')), - ], - ), - ] diff --git a/src/account/migrations/0004_downtime.py b/src/account/migrations/0004_downtime.py deleted file mode 100644 index fc700d1..0000000 --- a/src/account/migrations/0004_downtime.py +++ /dev/null @@ -1,24 +0,0 @@ -# Generated by Django 2.2 on 2019-08-13 16:45 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('account', '0003_publicnetwork'), - ] - - operations = [ - migrations.CreateModel( - name='Downtime', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('start', models.DateTimeField()), - ('end', models.DateTimeField()), - ('description', models.TextField(default='This lab will be down for maintenance')), - ('lab', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='account.Lab')), - ], - ), - ] diff --git a/src/account/migrations/0005_auto_20200723_2100.py b/src/account/migrations/0005_auto_20200723_2100.py deleted file mode 100644 index d995f80..0000000 --- a/src/account/migrations/0005_auto_20200723_2100.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 2.2 on 2020-07-23 21:00 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('account', '0004_downtime'), - ] - - operations = [ - migrations.AddField( - model_name='lab', - name='lab_info_link', - field=models.URLField(null=True), - ), - migrations.AddField( - model_name='lab', - name='project', - field=models.CharField(default='LaaS', max_length=100), - ), - ] diff --git a/src/account/migrations/0006_auto_20201109_1947.py b/src/account/migrations/0006_auto_20201109_1947.py deleted file mode 100644 index d08c426..0000000 --- a/src/account/migrations/0006_auto_20201109_1947.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 2.2 on 2020-11-09 19:47 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('account', '0005_auto_20200723_2100'), - ] - - operations = [ - migrations.AlterField( - model_name='userprofile', - name='full_name', - field=models.CharField(blank=True, default='', max_length=100, null=True), - ), - migrations.AlterField( - model_name='userprofile', - name='jira_url', - field=models.CharField(blank=True, default='', max_length=100, null=True), - ), - ] diff --git a/src/account/migrations/0007_userprofile_pulic_user.py b/src/account/migrations/0007_userprofile_pulic_user.py deleted file mode 100644 index 6a229e6..0000000 --- a/src/account/migrations/0007_userprofile_pulic_user.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 2.2 on 2021-03-24 21:06 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('account', '0006_auto_20201109_1947'), - ] - - operations = [ - migrations.AddField( - model_name='userprofile', - name='pulic_user', - field=models.BooleanField(default=False), - ), - ] diff --git a/src/account/migrations/0008_auto_20210324_2106.py b/src/account/migrations/0008_auto_20210324_2106.py deleted file mode 100644 index 9ff513d..0000000 --- a/src/account/migrations/0008_auto_20210324_2106.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 2.2 on 2021-03-24 21:06 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('account', '0007_userprofile_pulic_user'), - ] - - operations = [ - migrations.RenameField( - model_name='userprofile', - old_name='pulic_user', - new_name='public_user', - ), - ] diff --git a/src/account/migrations/0009_auto_20210324_2107.py b/src/account/migrations/0009_auto_20210324_2107.py deleted file mode 100644 index baa7382..0000000 --- a/src/account/migrations/0009_auto_20210324_2107.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 2.2 on 2021-03-24 21:07 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('account', '0008_auto_20210324_2106'), - ] - - operations = [ - migrations.AlterField( - model_name='userprofile', - name='public_user', - field=models.BooleanField(default=False), - ), - ] diff --git a/src/account/migrations/__init__.py b/src/account/migrations/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/src/account/migrations/__init__.py +++ /dev/null diff --git a/src/account/models.py b/src/account/models.py deleted file mode 100644 index 32229b1..0000000 --- a/src/account/models.py +++ /dev/null @@ -1,297 +0,0 @@ -############################################################################## -# Copyright (c) 2016 Max Breitenfeldt and others. -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -############################################################################## - - -from django.contrib.auth.models import User -from django.db import models -from django.apps import apps -import json -import random - -from collections import Counter - -from dashboard.exceptions import ResourceAvailabilityException - - -class LabStatus(object): - """ - A Poor man's enum for the status of a lab. - - If everything is working fine at a lab, it is UP. - If it is down temporarily e.g. for maintenance, it is TEMP_DOWN - If its broken, its DOWN - """ - - UP = 0 - TEMP_DOWN = 100 - DOWN = 200 - - -def upload_to(object, filename): - return object.user.username + '/' + filename - - -class UserProfile(models.Model): - """Extend the Django User model.""" - - user = models.OneToOneField(User, on_delete=models.CASCADE) - timezone = models.CharField(max_length=100, blank=False, default='UTC') - ssh_public_key = models.FileField(upload_to=upload_to, null=True, blank=True) - pgp_public_key = models.FileField(upload_to=upload_to, null=True, blank=True) - email_addr = models.CharField(max_length=300, blank=False, default='email@mail.com') - company = models.CharField(max_length=200, blank=False) - - oauth_token = models.CharField(max_length=1024, blank=False) - oauth_secret = models.CharField(max_length=1024, blank=False) - - jira_url = models.CharField(max_length=100, null=True, blank=True, default='') - - full_name = models.CharField(max_length=100, null=True, blank=True, default='') - booking_privledge = models.BooleanField(default=False) - - public_user = models.BooleanField(default=False) - - class Meta: - db_table = 'user_profile' - - def __str__(self): - return self.user.username - - -class VlanManager(models.Model): - """ - Keeps track of the vlans for a lab. - - Vlans are represented as indexes into a 4096 element list. - This list is serialized to JSON for storing in the DB. - """ - - # list of length 4096 containing either 0 (not available) or 1 (available) - vlans = models.TextField() - # list of length 4096 containing either 0 (not reserved) or 1 (reserved) - reserved_vlans = models.TextField() - - block_size = models.IntegerField() - - # True if the lab allows two different users to have the same private vlans - # if they use QinQ or a vxlan overlay, for example - allow_overlapping = models.BooleanField() - - def get_vlans(self, count=1, within=None): - """ - Return the IDs of available vlans as a list[int], but does not reserve them. - - Will throw index exception if not enough vlans are available. - Always returns a list of ints - - If `within` is not none, will filter against that as a set, requiring that any vlans returned are within that set - """ - allocated = [] - vlans = json.loads(self.vlans) - reserved = json.loads(self.reserved_vlans) - - for i in range(0, len(vlans) - 1): - if len(allocated) >= count: - break - - if vlans[i] == 0 and self.allow_overlapping is False: - continue - - if reserved[i] == 1: - continue - - # vlan is available and not reserved, so safe to add - if within is not None: - if i in within: - allocated.append(i) - else: - allocated.append(i) - continue - - if len(allocated) != count: - raise ResourceAvailabilityException("There were not enough available private vlans for the allocation. Please contact the administrators.") - - return allocated - - def get_public_vlan(self, within=None): - """Return reference to an available public network without reserving it.""" - r = PublicNetwork.objects.filter(lab=self.lab_set.first(), in_use=False) - if within is not None: - r = r.filter(vlan__in=within) - - if r.count() < 1: - raise ResourceAvailabilityException("There were not enough available public vlans for the allocation. Please contact the administrators.") - - return r.first() - - def reserve_public_vlan(self, vlan): - """Reserves the Public Network that has the given vlan.""" - net = PublicNetwork.objects.get(lab=self.lab_set.first(), vlan=vlan, in_use=False) - net.in_use = True - net.save() - - def release_public_vlan(self, vlan): - """Un-reserves a public network with the given vlan.""" - net = PublicNetwork.objects.get(lab=self.lab_set.first(), vlan=vlan, in_use=True) - net.in_use = False - net.save() - - def public_vlan_is_available(self, vlan): - """ - Whether the public vlan is available. - - returns true if the network with the given vlan is free to use, - False otherwise - """ - net = PublicNetwork.objects.get(lab=self.lab_set.first(), vlan=vlan) - return not net.in_use - - def is_available(self, vlans): - """ - If the vlans are available. - - 'vlans' is either a single vlan id integer or a list of integers - will return true (available) or false - """ - if self.allow_overlapping: - return True - - reserved = json.loads(self.reserved_vlans) - vlan_master_list = json.loads(self.vlans) - try: - iter(vlans) - except Exception: - vlans = [vlans] - - for vlan in vlans: - if not vlan_master_list[vlan] or reserved[vlan]: - return False - return True - - def release_vlans(self, vlans): - """ - Make the vlans available for another booking. - - 'vlans' is either a single vlan id integer or a list of integers - will make the vlans available - doesnt return a value - """ - my_vlans = json.loads(self.vlans) - - try: - iter(vlans) - except Exception: - vlans = [vlans] - - for vlan in vlans: - my_vlans[vlan] = 1 - self.vlans = json.dumps(my_vlans) - self.save() - - def reserve_vlans(self, vlans): - """ - Reserves all given vlans or throws a ValueError. - - vlans can be an integer or a list of integers. - """ - my_vlans = json.loads(self.vlans) - - reserved = json.loads(self.reserved_vlans) - - try: - iter(vlans) - except Exception: - vlans = [vlans] - - vlans = set(vlans) - - for vlan in vlans: - if my_vlans[vlan] == 0 or reserved[vlan] == 1: - raise ValueError("vlan " + str(vlan) + " is not available") - - my_vlans[vlan] = 0 - self.vlans = json.dumps(my_vlans) - self.save() - - -class Lab(models.Model): - """ - Model representing a Hosting Lab. - - Anybody that wants to host resources for LaaS needs to have a Lab model - We associate hardware with Labs so we know what is available and where. - """ - - lab_user = models.OneToOneField(User, on_delete=models.CASCADE) - name = models.CharField(max_length=200, primary_key=True, unique=True, null=False, blank=False) - contact_email = models.EmailField(max_length=200, null=True, blank=True) - contact_phone = models.CharField(max_length=20, null=True, blank=True) - status = models.IntegerField(default=LabStatus.UP) - vlan_manager = models.ForeignKey(VlanManager, on_delete=models.CASCADE, null=True) - location = models.TextField(default="unknown") - # This token must apear in API requests from this lab - api_token = models.CharField(max_length=50) - description = models.CharField(max_length=240) - lab_info_link = models.URLField(null=True) - project = models.CharField(default='LaaS', max_length=100) - - @staticmethod - def make_api_token(): - """Generate random 45 character string for API token.""" - alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" - key = "" - for i in range(45): - key += random.choice(alphabet) - return key - - def get_available_resources(self): - # Cannot import model normally due to ciruclar import - Server = apps.get_model('resource_inventory', 'Server') # TODO: Find way to import ResourceQuery - resources = [str(resource.profile) for resource in Server.objects.filter(lab=self, working=True, booked=False)] - return dict(Counter(resources)) - - def __str__(self): - return self.name - - -class PublicNetwork(models.Model): - """L2/L3 network that can reach the internet.""" - - vlan = models.IntegerField() - lab = models.ForeignKey(Lab, on_delete=models.CASCADE) - in_use = models.BooleanField(default=False) - cidr = models.CharField(max_length=50, default="0.0.0.0/0") - gateway = models.CharField(max_length=50, default="0.0.0.0") - - -class Downtime(models.Model): - """ - A Downtime event. - - Labs can create Downtime objects so the dashboard can - alert users that the lab is down, etc - """ - - start = models.DateTimeField() - end = models.DateTimeField() - lab = models.ForeignKey(Lab, on_delete=models.CASCADE) - description = models.TextField(default="This lab will be down for maintenance") - - def save(self, *args, **kwargs): - if self.start >= self.end: - raise ValueError('Start date is after end date') - - # check for overlapping downtimes - overlap_start = Downtime.objects.filter(lab=self.lab, start__gt=self.start, start__lt=self.end).exists() - overlap_end = Downtime.objects.filter(lab=self.lab, end__lt=self.end, end__gt=self.start).exists() - - if overlap_start or overlap_end: - raise ValueError('Overlapping Downtime') - - return super(Downtime, self).save(*args, **kwargs) diff --git a/src/account/tests/__init__.py b/src/account/tests/__init__.py deleted file mode 100644 index b6fef6c..0000000 --- a/src/account/tests/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -############################################################################## -# Copyright (c) 2016 Max Breitenfeldt and others. -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -############################################################################## diff --git a/src/account/tests/test_general.py b/src/account/tests/test_general.py deleted file mode 100644 index 4020d89..0000000 --- a/src/account/tests/test_general.py +++ /dev/null @@ -1,60 +0,0 @@ -############################################################################## -# Copyright (c) 2016 Max Breitenfeldt and others. -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -############################################################################## - - -from django.contrib.auth.models import User -from django.test import Client -from django.test import TestCase -from django.urls import reverse -from django.utils import timezone - -from account.models import UserProfile - - -class AccountMiddlewareTestCase(TestCase): - def setUp(self): - self.client = Client() - self.user1 = User.objects.create(username='user1') - self.user1.set_password('user1') - self.user1profile = UserProfile.objects.create(user=self.user1) - self.user1.save() - - def test_timezone_middleware(self): - """ - Verify timezone is being set by Middleware. - - The timezone should be UTC for anonymous users, - for authenticated users it should be set to user.userprofile.timezone - """ - # default - self.assertEqual(timezone.get_current_timezone_name(), 'UTC') - - url = reverse('account:settings') - # anonymous request - self.client.get(url) - self.assertEqual(timezone.get_current_timezone_name(), 'UTC') - - # authenticated user with UTC timezone (userprofile default) - self.client.login(username='user1', password='user1') - self.client.get(url) - self.assertEqual(timezone.get_current_timezone_name(), 'UTC') - - # authenticated user with custom timezone (userprofile default) - self.user1profile.timezone = 'Etc/Greenwich' - self.user1profile.save() - self.client.get(url) - self.assertEqual(timezone.get_current_timezone_name(), 'GMT') - - # if there is no profile for a user, it should be created - user2 = User.objects.create(username='user2') - user2.set_password('user2') - user2.save() - self.client.login(username='user2', password='user2') - self.client.get(url) - self.assertTrue(user2.userprofile) diff --git a/src/account/urls.py b/src/account/urls.py deleted file mode 100644 index 6d4ef2f..0000000 --- a/src/account/urls.py +++ /dev/null @@ -1,59 +0,0 @@ -############################################################################## -# Copyright (c) 2016 Max Breitenfeldt and others. -# Copyright (c) 2018 Parker Berberian, Sawyer Bergeron, and others. -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -############################################################################## - - -""" -laas_dashboard URL Configuration. - -The `urlpatterns` list routes URLs to views. For more information please see: - https://docs.djangoproject.com/en/1.10/topics/http/urls/ -Examples: -Function views - 1. Add an import: from my_app import views - 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') -Class-based views - 1. Add an import: from other_app.views import Home - 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') -Including another URLconf - 1. Import the include() function: from django.conf.urls import url, include - 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) -""" -from django.conf.urls import url -from django.urls import path - -from account.views import ( - AccountSettingsView, - OIDCLoginView, - LogoutView, - UserListView, - account_resource_view, - account_booking_view, - account_images_view, - account_detail_view, - template_delete_view, - booking_cancel_view, - image_delete_view, -) - -app_name = 'account' - -urlpatterns = [ - url(r'^settings/', AccountSettingsView.as_view(), name='settings'), - url(r'^login/$', OIDCLoginView.as_view(), name='login'), - url(r'^logout/$', LogoutView.as_view(), name='logout'), - url(r'^users/$', UserListView.as_view(), name='users'), - url(r'^my/resources/$', account_resource_view, name='my-resources'), - path('my/resources/delete/<int:resource_id>', template_delete_view), - url(r'^my/bookings/$', account_booking_view, name='my-bookings'), - path('my/bookings/cancel/<int:booking_id>', booking_cancel_view), - url(r'^my/images/$', account_images_view, name='my-images'), - path('my/images/delete/<int:image_id>', image_delete_view), - url(r'^my/$', account_detail_view, name='my-account'), -] diff --git a/src/account/views.py b/src/account/views.py deleted file mode 100644 index 8976ff9..0000000 --- a/src/account/views.py +++ /dev/null @@ -1,226 +0,0 @@ -############################################################################## -# Copyright (c) 2016 Max Breitenfeldt and others. -# Copyright (c) 2018 Parker Berberian, Sawyer Bergeron, and others. -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -############################################################################## - - -import os - -from django.utils import timezone -from django.contrib import messages -from django.contrib.auth import logout -from django.contrib.auth.decorators import login_required -from django.contrib.auth.mixins import LoginRequiredMixin -from django.contrib.auth.models import User -from django.urls import reverse -from django.http import HttpResponse -from django.shortcuts import get_object_or_404 -from django.utils.decorators import method_decorator -from django.views.generic import RedirectView, TemplateView, UpdateView -from django.shortcuts import render -from rest_framework.authtoken.models import Token -from mozilla_django_oidc.auth import OIDCAuthenticationBackend - - -from account.forms import AccountSettingsForm -from account.models import UserProfile -from booking.models import Booking -from resource_inventory.models import ResourceTemplate, Image - - -@method_decorator(login_required, name='dispatch') -class AccountSettingsView(UpdateView): - model = UserProfile - form_class = AccountSettingsForm - template_name_suffix = '_update_form' - - def get_success_url(self): - messages.add_message(self.request, messages.INFO, - 'Settings saved') - return '/' - - def get_object(self, queryset=None): - return self.request.user.userprofile - - def get_context_data(self, **kwargs): - token, created = Token.objects.get_or_create(user=self.request.user) - context = super(AccountSettingsView, self).get_context_data(**kwargs) - context.update({'title': "Settings", 'token': token}) - return context - - -class MyOIDCAB(OIDCAuthenticationBackend): - def filter_users_by_claims(self, claims): - """ - Checks to see if user exists and create user if not - - Linux foundation does not allow users to change their - username, so chose to match users based on their username. - If this changes we will need to match users based on some - other criterea. - """ - username = claims.get(os.environ.get('CLAIMS_ENDPOINT') + 'username') - - if not username: - return HttpResponse('No username provided, contact support.') - - try: - # For literally no (good) reason user needs to be a queryset - user = User.objects.filter(username=username) - return user - except User.DoesNotExist: - return self.UserModel.objects.none() - - def create_user(self, claims): - """ This creates a user and user profile""" - user = super(MyOIDCAB, self).create_user(claims) - user.username = claims.get(os.environ['CLAIMS_ENDPOINT'] + 'username') - user.save() - - up = UserProfile() - up.user = user - up.email_addr = claims.get('email') - up.save() - return user - - def update_user(self, user, claims): - """ If their account has different email, change the email """ - up = UserProfile.objects.get(user=user) - up.email_addr = claims.get('email') - up.save() - return user - - -class OIDCLoginView(RedirectView): - def get_redirect_url(self, *args, **kwargs): - return reverse('oidc_authentication_init') - - -class LogoutView(LoginRequiredMixin, RedirectView): - def get_redirect_url(self, *args, **kwargs): - logout(self.request) - return '/' - - -@method_decorator(login_required, name='dispatch') -class UserListView(TemplateView): - template_name = "account/user_list.html" - - def get_context_data(self, **kwargs): - users = UserProfile.objects.filter(public_user=True).select_related('user') - context = super(UserListView, self).get_context_data(**kwargs) - context.update({'title': "Dashboard Users", 'users': users}) - return context - - -def account_detail_view(request): - template = "account/details.html" - return render(request, template) - - -def account_resource_view(request): - """ - Display a user's resources. - - gathers a users genericResoureBundles and - turns them into displayable objects - """ - if not request.user.is_authenticated: - return render(request, "dashboard/login.html", {'title': 'Authentication Required'}) - template = "account/resource_list.html" - - active_bundles = [book.resource for book in Booking.objects.filter( - owner=request.user, end__gte=timezone.now(), resource__template__temporary=False)] - active_resources = [bundle.template.id for bundle in active_bundles] - resource_list = list(ResourceTemplate.objects.filter(owner=request.user, temporary=False)) - - context = { - "resources": resource_list, - "active_resources": active_resources, - "title": "My Resources" - } - return render(request, template, context=context) - - -def account_booking_view(request): - if not request.user.is_authenticated: - return render(request, "dashboard/login.html", {'title': 'Authentication Required'}) - template = "account/booking_list.html" - bookings = list(Booking.objects.filter(owner=request.user, end__gt=timezone.now()).order_by("-start")) - my_old_bookings = Booking.objects.filter(owner=request.user, end__lt=timezone.now()).order_by("-start") - collab_old_bookings = request.user.collaborators.filter(end__lt=timezone.now()).order_by("-start") - expired_bookings = list(my_old_bookings.union(collab_old_bookings)) - collab_bookings = list(request.user.collaborators.filter(end__gt=timezone.now()).order_by("-start")) - context = { - "title": "My Bookings", - "bookings": bookings, - "collab_bookings": collab_bookings, - "expired_bookings": expired_bookings - } - return render(request, template, context=context) - - -def account_images_view(request): - if not request.user.is_authenticated: - return render(request, "dashboard/login.html", {'title': 'Authentication Required'}) - template = "account/image_list.html" - my_images = Image.objects.filter(owner=request.user) - public_images = Image.objects.filter(public=True) - used_images = {} - for image in my_images: - if image.in_use(): - used_images[image.id] = "true" - context = { - "title": "Images", - "images": my_images, - "public_images": public_images, - "used_images": used_images - } - return render(request, template, context=context) - - -def template_delete_view(request, resource_id=None): - if not request.user.is_authenticated: - return HttpResponse(status=403) - template = get_object_or_404(ResourceTemplate, pk=resource_id) - if not request.user.id == template.owner.id: - return HttpResponse(status=403) - if Booking.objects.filter(resource__template=template, end__gt=timezone.now()).exists(): - return HttpResponse(status=403) - template.public = False - template.temporary = True - template.save() - return HttpResponse(status=200) - - -def booking_cancel_view(request, booking_id=None): - if not request.user.is_authenticated: - return HttpResponse('no') # 403? - booking = get_object_or_404(Booking, pk=booking_id) - if not request.user.id == booking.owner.id: - return HttpResponse('no') # 403? - - if booking.end < timezone.now(): # booking already over - return HttpResponse('') - - booking.end = timezone.now() - booking.save() - return HttpResponse('') - - -def image_delete_view(request, image_id=None): - if not request.user.is_authenticated: - return HttpResponse('no') # 403? - image = get_object_or_404(Image, pk=image_id) - if image.public or image.owner.id != request.user.id: - return HttpResponse('no') # 403? - # check if used in booking - if image.in_use(): - return HttpResponse('no') # 403? - image.delete() - return HttpResponse('') |