Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NN API Route #90

Merged
merged 33 commits into from
Dec 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
a665053
First stab at NN API route
WillNilges Dec 10, 2023
f29c48a
Add more tests
WillNilges Dec 10, 2023
8ef1d1d
Add more robust test
WillNilges Dec 10, 2023
ea42376
Andy comments 1/n
WillNilges Dec 20, 2023
f2afed1
Refactor to NetworkNumberAssignment
WillNilges Dec 22, 2023
1b52e9d
Hardcode highest network number
WillNilges Dec 22, 2023
998a69f
Remove redundant Request fields
WillNilges Dec 22, 2023
f3154fe
Update Models, remove Request
WillNilges Dec 22, 2023
7a5309a
Swap request for install
WillNilges Dec 22, 2023
9861ee2
Update status and find an install number
WillNilges Dec 22, 2023
8cc7cc5
Make tests work again
WillNilges Dec 22, 2023
d1230ef
Add member moved test
WillNilges Dec 22, 2023
9a46539
Update NN route
WillNilges Dec 22, 2023
3cd2449
Update join form and nn form
WillNilges Dec 23, 2023
7920112
andrew updates 1
WillNilges Dec 23, 2023
90242f3
Andrew changes 2
WillNilges Dec 23, 2023
22c39c4
ugh
WillNilges Dec 23, 2023
ff46c6f
blargh
WillNilges Dec 23, 2023
f254ce5
I hate computers
WillNilges Dec 23, 2023
0e014b6
Tests pass
WillNilges Dec 24, 2023
ce85c56
fuck
WillNilges Dec 24, 2023
782e81d
make big test work
WillNilges Dec 24, 2023
ed45273
Update member object creation
WillNilges Dec 24, 2023
85aaa82
datetime
WillNilges Dec 24, 2023
360be60
squash part 1
WillNilges Dec 24, 2023
4dc0540
nuke migrations
WillNilges Dec 24, 2023
b1acc3a
nuke migrations II electic boogalooo
WillNilges Dec 24, 2023
8e97acc
timezone
WillNilges Dec 24, 2023
cedc588
black
WillNilges Dec 24, 2023
eb72341
Bring back referral field
WillNilges Dec 24, 2023
eb0ef31
andrew comments 4
WillNilges Dec 24, 2023
962a95a
migrations
WillNilges Dec 24, 2023
6573316
make tests pass
WillNilges Dec 24, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
Andrew-Dickinson marked this conversation as resolved.
Show resolved Hide resolved
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)
WillNilges marked this conversation as resolved.
Show resolved Hide resolved
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