Skip to content

Commit

Permalink
NN API Route (#90)
Browse files Browse the repository at this point in the history
* First stab at NN API route

* Add more tests

* Add more robust test

* Andy comments 1/n

* Refactor to NetworkNumberAssignment

* Hardcode highest network number

* Remove redundant Request fields

* Update Models, remove Request

* Swap request for install

* Update status and find an install number

* Make tests work again

* Add member moved test

* Update NN route

* Update join form and nn form

* andrew updates 1

* Andrew changes 2

* ugh

* blargh

* I hate computers

* Tests pass

* fuck

* make big test work

* Update member object creation

* datetime

* squash part 1

* nuke migrations

* nuke migrations II electic boogalooo

* timezone

* black

* Bring back referral field

* andrew comments 4

* migrations

* make tests pass
  • Loading branch information
WillNilges authored Dec 25, 2023
1 parent 419d051 commit a40ed1c
Show file tree
Hide file tree
Showing 12 changed files with 499 additions and 231 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Generated by Django 4.2.5 on 2023-10-26 01:46
# Generated by Django 4.2.5 on 2023-12-24 23:23

import django.contrib.auth.models
import django.contrib.postgres.fields
import django.core.validators
from django.db import migrations, models
import django.db.models.deletion

Expand All @@ -13,6 +15,27 @@ class Migration(migrations.Migration):
]

operations = [
migrations.CreateModel(
name="Admin",
fields=[
(
"group_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="auth.group",
),
),
("description", models.TextField(blank=True, max_length=100)),
],
bases=("auth.group",),
managers=[
("objects", django.contrib.auth.models.GroupManager()),
],
),
migrations.CreateModel(
name="Building",
fields=[
Expand All @@ -26,9 +49,29 @@ class Migration(migrations.Migration):
("latitude", models.FloatField()),
("longitude", models.FloatField()),
("altitude", models.FloatField()),
("network_number", models.IntegerField(blank=True, null=True)),
("install_date", models.DateField(blank=True, default=None, null=True)),
("abandon_date", models.DateField(blank=True, default=None, null=True)),
("primary_nn", models.IntegerField(blank=True, null=True)),
("node_name", models.TextField(blank=True, default=None, null=True)),
],
),
migrations.CreateModel(
name="Installer",
fields=[
(
"group_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="auth.group",
),
),
("description", models.TextField(blank=True, max_length=100)),
],
bases=("auth.group",),
managers=[
("objects", django.contrib.auth.models.GroupManager()),
],
),
migrations.CreateModel(
Expand All @@ -38,25 +81,18 @@ class Migration(migrations.Migration):
("first_name", models.TextField()),
("last_name", models.TextField()),
("email_address", models.EmailField(max_length=254)),
(
"secondary_emails",
django.contrib.postgres.fields.ArrayField(
base_field=models.EmailField(max_length=254), null=True, size=None
),
),
("phone_number", models.TextField(blank=True, default=None, null=True)),
("slack_handle", models.TextField(blank=True, default=None, null=True)),
],
),
migrations.CreateModel(
name="Install",
fields=[
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
("install_number", models.IntegerField()),
("install_status", models.IntegerField(choices=[(0, "Planned"), (1, "Inactive"), (2, "Active")])),
("building_id", models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to="meshapi.building")),
("member_id", models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to="meshapi.member")),
("abandon_date", models.DateField(blank=True, default=None, null=True)),
("install_date", models.DateField(blank=True, default=None, null=True)),
("unit", models.TextField(blank=True, default=None, null=True)),
],
),
migrations.CreateModel(
name="Installer",
name="ReadOnly",
fields=[
(
"group_ptr",
Expand All @@ -77,22 +113,44 @@ class Migration(migrations.Migration):
],
),
migrations.CreateModel(
name="Request",
name="Install",
fields=[
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
("request_status", models.IntegerField(choices=[(0, "Open"), (1, "Closed"), (2, "Installed")])),
("ticket_id", models.IntegerField(blank=True, null=True)),
("building_id", models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to="meshapi.building")),
("install_number", models.AutoField(db_column="install_number", primary_key=True, serialize=False)),
(
"install_id",
models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to="meshapi.install"
"network_number",
models.IntegerField(
blank=True,
null=True,
validators=[
django.core.validators.MinValueValidator(101),
django.core.validators.MaxValueValidator(8192),
],
),
),
("member_id", models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to="meshapi.member")),
(
"install_status",
models.IntegerField(
choices=[
(0, "Open"),
(1, "Scheduled"),
(2, "Nn Assigned"),
(3, "Blocked"),
(4, "Active"),
(5, "Inactive"),
(6, "Closed"),
]
),
),
("ticket_id", models.IntegerField(blank=True, null=True)),
("request_date", models.DateField(blank=True, default=None, null=True)),
("install_date", models.DateField(blank=True, default=None, null=True)),
("abandon_date", models.DateField(blank=True, default=None, null=True)),
("unit", models.TextField(blank=True, default=None, null=True)),
("roof_access", models.BooleanField(default=False)),
("referral", models.TextField(blank=True, default=None, null=True)),
("unit", models.TextField(blank=True, default=None, null=True)),
("notes", models.TextField(blank=True, default=None, null=True)),
("building_id", models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to="meshapi.building")),
("member_id", models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to="meshapi.member")),
],
),
]
21 changes: 0 additions & 21 deletions src/meshapi/migrations/0016_create_default_groups.py

This file was deleted.

85 changes: 59 additions & 26 deletions src/meshapi/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models
from django.contrib.postgres.fields import ArrayField

from django.contrib.auth.models import Group
from django.db.models.fields import EmailField

NETWORK_NUMBER_MIN = 101
NETWORK_NUMBER_MAX = 8192


class Installer(Group):
Expand All @@ -10,6 +16,20 @@ def __str__(self):
return self.name


class Admin(Group):
description = models.TextField(max_length=100, blank=True)

def __str__(self):
return self.name


class ReadOnly(Group):
description = models.TextField(max_length=100, blank=True)

def __str__(self):
return self.name


class Building(models.Model):
class BuildingStatus(models.IntegerChoices):
INACTIVE = 0
Expand All @@ -24,47 +44,60 @@ class BuildingStatus(models.IntegerChoices):
latitude = models.FloatField()
longitude = models.FloatField()
altitude = models.FloatField()
network_number = models.IntegerField(blank=True, null=True)
install_date = models.DateField(default=None, blank=True, null=True)
abandon_date = models.DateField(default=None, blank=True, null=True)
primary_nn = models.IntegerField(blank=True, null=True)
node_name = models.TextField(default=None, blank=True, null=True)


class Member(models.Model):
first_name = models.TextField()
last_name = models.TextField()
email_address = models.EmailField()
phone_number = models.TextField(
default=None, blank=True, null=True
) # TODO (willnilges): Can we get some validation on this?
secondary_emails = ArrayField(EmailField(), null=True)
phone_number = models.TextField(default=None, blank=True, null=True)
slack_handle = models.TextField(default=None, blank=True, null=True)


class Install(models.Model):
class InstallStatus(models.IntegerChoices):
PLANNED = 0
INACTIVE = 1
ACTIVE = 2
OPEN = 0
SCHEDULED = 1
NN_ASSIGNED = 2
BLOCKED = 3
ACTIVE = 4
INACTIVE = 5
CLOSED = 6

install_number = models.IntegerField()
install_status = models.IntegerField(choices=InstallStatus.choices)
building_id = models.ForeignKey(Building, on_delete=models.PROTECT)
unit = models.TextField(default=None, blank=True, null=True)
member_id = models.ForeignKey(Member, on_delete=models.PROTECT)
install_date = models.DateField(default=None, blank=True, null=True)
abandon_date = models.DateField(default=None, blank=True, null=True)
# Install Number (generated when form is submitted)
install_number = models.AutoField(
primary_key=True,
db_column="install_number",
)

# The NN this install is associated with.
# Through this, a building can have multiple NNs
network_number = models.IntegerField(
blank=True,
null=True,
validators=[MinValueValidator(NETWORK_NUMBER_MIN), MaxValueValidator(NETWORK_NUMBER_MAX)],
)

class Request(models.Model):
class RequestStatus(models.IntegerChoices):
OPEN = 0
CLOSED = 1
INSTALLED = 2
# Summary status of install
install_status = models.IntegerField(choices=InstallStatus.choices)

request_status = models.IntegerField(choices=RequestStatus.choices)
roof_access = models.BooleanField(default=False)
referral = models.TextField(default=None, blank=True, null=True)
# OSTicket ID
ticket_id = models.IntegerField(blank=True, null=True)
member_id = models.ForeignKey(Member, on_delete=models.PROTECT)

# Important dates
request_date = models.DateField(default=None, blank=True, null=True)
install_date = models.DateField(default=None, blank=True, null=True)
abandon_date = models.DateField(default=None, blank=True, null=True)

# Relation to Building
building_id = models.ForeignKey(Building, on_delete=models.PROTECT)
unit = models.TextField(default=None, blank=True, null=True)
install_id = models.ForeignKey(Install, on_delete=models.PROTECT, blank=True, null=True)
roof_access = models.BooleanField(default=False)

# Relation to Member
member_id = models.ForeignKey(Member, on_delete=models.PROTECT)
referral = models.TextField(default=None, blank=True, null=True)
notes = models.TextField(default=None, blank=True, null=True)
23 changes: 4 additions & 19 deletions src/meshapi/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,23 +111,8 @@ def has_permission(self, request, view):
return True


# Anyone can view requests, but only installers and admins can create them
class RequestListCreatePermissions(permissions.BasePermission):
class NetworkNumberAssignmentPermissions(permissions.BasePermission):
def has_permission(self, request, view):
if request.method == "GET":
return True
else:
if not request.user.is_superuser or is_admin(request.user):
raise PermissionDenied(perm_denied_generic_msg)
return True


# Anyone can retrieve requests, but only an admin can do anything else
class RequestRetrieveUpdateDestroyPermissions(permissions.BasePermission):
def has_permission(self, request, view):
if request.method == "GET":
return True
else:
if not request.user.is_superuser or is_admin(request.user):
raise PermissionDenied(perm_denied_generic_msg)
return True
if not (request.user.is_superuser or is_admin(request.user) or is_installer(request.user)):
raise PermissionDenied(perm_denied_generic_msg)
return True
8 changes: 1 addition & 7 deletions src/meshapi/serializers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from django.contrib.auth.models import User
from rest_framework import serializers
from meshapi.models import Building, Member, Install, Request
from meshapi.models import Building, Member, Install


class UserSerializer(serializers.ModelSerializer):
Expand All @@ -25,9 +25,3 @@ class InstallSerializer(serializers.ModelSerializer):
class Meta:
model = Install
fields = "__all__"


class RequestSerializer(serializers.ModelSerializer):
class Meta:
model = Request
fields = "__all__"
21 changes: 8 additions & 13 deletions src/meshapi/tests/sample_data.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from meshapi.models import Install, Request
from meshapi.models import Install

sample_member = {
"first_name": "John",
Expand All @@ -18,24 +18,19 @@
"latitude": 0.0,
"longitude": 0.0,
"altitude": 0.0,
"network_number": 9001,
"install_date": "2222-02-02",
"abandon_date": "",
"primary_nn": 2000,
}

sample_install = {
"install_number": 420,
"network_number": 2000,
"install_status": Install.InstallStatus.ACTIVE,
"ticket_id": 69,
"request_date": "2022-02-27",
"install_date": "2022-03-01",
"abandon_date": "",
"member_id": 1,
"building_id": 1,
}

sample_request = {
"request_status": Request.RequestStatus.OPEN,
"ticket_id": 1,
"unit": 3,
"roof_access": True,
"member_id": 1,
"building_id": 1,
"install_id": "",
"notes": "Referral: Read about it on the internet",
}
Loading

0 comments on commit a40ed1c

Please sign in to comment.