aboutsummaryrefslogtreecommitdiffstats
path: root/src/account/models.py
blob: bb1cad51366ce842e980a849f85f3a93260b565d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
##############################################################################
# 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

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')
    email_addr = models.CharField(max_length=300, blank=False, default='email@mail.com')

    oauth_token = models.CharField(max_length=1024, blank=False)
    oauth_secret = models.CharField(max_length=1024, blank=False)

    full_name = models.CharField(max_length=100, null=True, blank=True, default='')
    booking_privledge = models.BooleanField(default=False)

    public_user = models.BooleanField(default=False)
    ipa_username = models.CharField(max_length=100, null=True, blank=True)

    class Meta:
        db_table = 'user_profile'

    def __str__(self):
        return self.user.username

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)
    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 __str__(self):
        return self.name

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)