Skip to content
This repository was archived by the owner on Dec 19, 2021. It is now read-only.

Commit e358b30

Browse files
authored
Remove set_property_managers method (#181)
* Remove property init method * Validate uniqueness of name in Property Schema * Remove reqparser * Remove set_managers method * Use the create method for creating Property seeds * Add nullable False to archive field
1 parent 41cde2d commit e358b30

File tree

10 files changed

+144
-190
lines changed

10 files changed

+144
-190
lines changed

conftest.py

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99
import jwt
1010
from tests.factory_fixtures import *
1111

12-
newPropertyName = "myNewProperty"
13-
newPropertyAddress = "123 NE FLanders St"
1412
plaintext_password = "1234"
1513

1614
# Note: this repo uses the "pytest-flask" plugin which exposes the following fixtures for use in tests:
@@ -93,19 +91,6 @@ def pm_header(create_property_manager):
9391
).decode('utf-8')
9492
return {"Authorization": f"Bearer {token}"}
9593

96-
@pytest.fixture
97-
def new_property():
98-
newProperty = PropertyModel( name=newPropertyName
99-
, address=newPropertyAddress
100-
, city="Portland"
101-
, unit="101"
102-
, state="OR"
103-
, zipcode="97207"
104-
, propertyManagerIDs=[5]
105-
, archived=0
106-
)
107-
return newProperty
108-
10994
@pytest.fixture
11095
def test_database(app, admin_user, new_user, property_manager_user):
11196
db.create_all()

data/seedData.py

Lines changed: 43 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
from models.contact_number import ContactNumberModel
1212
from models.lease import LeaseModel
1313
from utils.time import time_format
14+
from schemas import PropertySchema
15+
1416

1517
def seedData():
1618
now=datetime.utcnow()
@@ -114,33 +116,47 @@ def seedData():
114116
archived=False)
115117
user_xander_dander.save_to_db()
116118

117-
property_test1 = PropertyModel(name="test1",
118-
address="123 NE FLanders St",
119-
unit="5",
120-
city="Portland",
121-
state="OR",
122-
zipcode="97207",
123-
propertyManagerIDs=[user_gray_pouponn.id],
124-
archived=False)
125-
property_test1.save_to_db()
126-
property_meerkat_manor = PropertyModel(name="Meerkat Manor",
127-
address="Privet Drive",
128-
unit="2",
129-
city="Portland",
130-
state="OR",
131-
zipcode="97207",
132-
propertyManagerIDs=[user_mister_sir.id],
133-
archived=False)
134-
property_meerkat_manor.save_to_db()
135-
property_the_reginald = PropertyModel(name="The Reginald",
136-
address="Aristocrat Avenue",
137-
unit="3",
138-
city="Portland",
139-
state="OR",
140-
zipcode="97207",
141-
propertyManagerIDs=[user_gray_pouponn.id, user_mister_sir.id],
142-
archived=False)
143-
property_the_reginald.save_to_db()
119+
120+
property_test1 = PropertyModel.create(
121+
payload= {
122+
'name': "test1",
123+
'address': "123 NE FLanders St",
124+
'unit': "5",
125+
'city': "Portland",
126+
'state': "OR",
127+
'zipcode': "97207",
128+
'propertyManagerIDs': [user_gray_pouponn.id]
129+
},
130+
schema=PropertySchema
131+
)
132+
133+
134+
property_meerkat_manor = PropertyModel.create(
135+
payload = {
136+
'name': "Meerkat Manor",
137+
'address': "Privet Drive",
138+
'unit': "2",
139+
'city': "Portland",
140+
'state': "OR",
141+
'zipcode': "97207",
142+
'propertyManagerIDs': [user_mister_sir.id]
143+
},
144+
schema = PropertySchema
145+
)
146+
147+
property_the_reginald = PropertyModel.create(
148+
payload = {
149+
'name': "The Reginald",
150+
'address': "Aristocrat Avenue",
151+
'unit': "3",
152+
'city': "Portland",
153+
'state': "OR",
154+
'zipcode': "97207",
155+
'propertyManagerIDs': [user_gray_pouponn.id, user_mister_sir.id]
156+
},
157+
schema = PropertySchema
158+
)
159+
144160

145161
tenant_renty_mcrenter = TenantModel(firstName="Renty",
146162
lastName="McRenter",

models/base_model.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,7 @@ def __repr__(self):
6666
@classmethod
6767
def _name(cls):
6868
return cls.__name__.replace('Model', '')
69+
70+
@classmethod
71+
def tablename(cls):
72+
return cls.__tablename__

models/property.py

Lines changed: 3 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
from db import db
22
from utils.time import Time
3-
from marshmallow import ValidationError
43

54
from models.tenant import TenantModel
65
from models.base_model import BaseModel
7-
from models.user import UserModel, RoleEnum
6+
from models.user import UserModel
87
from models.property_assignment import PropertyAssignment
98

109

@@ -18,20 +17,10 @@ class PropertyModel(BaseModel):
1817
city = db.Column(db.String(50))
1918
state = db.Column(db.String(50))
2019
zipcode = db.Column(db.String(20))
21-
archived = db.Column(db.Boolean)
20+
archived = db.Column(db.Boolean, default=False, nullable=False)
2221

2322
leases = db.relationship('LeaseModel', backref='property', lazy=True, cascade="all, delete-orphan")
24-
managers = db.relationship(UserModel, secondary='property_assignments', backref='properties')
25-
26-
def __init__(self, name, address, unit, city, state, zipcode, propertyManagerIDs, archived):
27-
self.name = name
28-
self.address = address
29-
self.unit = unit
30-
self.city = city
31-
self.state = state
32-
self.zipcode = zipcode
33-
self.managers = self.set_property_managers(propertyManagerIDs)
34-
self.archived = False
23+
managers = db.relationship(UserModel, secondary=PropertyAssignment.tablename(), backref='properties')
3524

3625
def json(self):
3726

@@ -59,20 +48,3 @@ def find_by_name(cls, name):
5948
@classmethod
6049
def find_by_manager(cls, manager_id):
6150
return cls.query.filter(cls.managers.any(UserModel.id == manager_id)).all()
62-
63-
@classmethod
64-
def set_property_managers(cls, ids):
65-
managers = []
66-
if ids:
67-
for id in ids:
68-
user = UserModel.find_by_id(id)
69-
if user and user.role == RoleEnum.PROPERTY_MANAGER:
70-
71-
managers.append(user)
72-
73-
elif user and user.role != RoleEnum.PROPERTY_MANAGER:
74-
raise ValidationError(f'{user.full_name()} is not a property manager')
75-
else:
76-
raise ValidationError(f'{id} is not a valid user id')
77-
78-
return managers

resources/property.py

Lines changed: 4 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import json
21
from flask_restful import Resource, reqparse
2+
from flask import request
33
from utils.authorizations import admin_required
44
from db import db
55
from models.property import PropertyModel
6+
from schemas.property import PropertySchema
67

78
# | method | route | action |
89
# | :----- | :------------------- | :------------------------- |
@@ -12,35 +13,15 @@
1213
# | PUT | `v1/property/:id` | Updates a single property |
1314
# | DELETE | `v1/property/:id` | Deletes a single property |
1415

15-
#TODO Add Id based identifiers.
1616
#TODO Incorporate JWT Claims for Admin
1717

1818
class Properties(Resource):
19-
parser = reqparse.RequestParser()
20-
parser.add_argument('name')
21-
parser.add_argument('address')
22-
parser.add_argument('unit')
23-
parser.add_argument('city')
24-
parser.add_argument('zipcode')
25-
parser.add_argument('state')
26-
parser.add_argument('propertyManagerIDs')
27-
parser.add_argument('archived')
28-
2919
def get(self):
3020
return {'properties': [property.json() for property in db.session.query(PropertyModel).all()]}
3121

3222
@admin_required
3323
def post(self):
34-
data = Properties.parser.parse_args()
35-
36-
if PropertyModel.find_by_name(data["name"]):
37-
return { 'message': 'A property with this name already exists'}, 401
38-
39-
rentalproperty = PropertyModel(**data)
40-
41-
PropertyModel.save_to_db(rentalproperty)
42-
43-
return rentalproperty.json(), 201
24+
return PropertyModel.create(schema=PropertySchema, payload=request.json).json(), 201
4425

4526
class ArchiveProperty(Resource):
4627

@@ -81,17 +62,6 @@ def patch(self):
8162

8263
# single property/name
8364
class Property(Resource):
84-
parser = reqparse.RequestParser()
85-
parser.add_argument('name')
86-
parser.add_argument('address')
87-
parser.add_argument('unit')
88-
parser.add_argument('city')
89-
parser.add_argument('zipcode')
90-
parser.add_argument('state')
91-
parser.add_argument('propertyManagerIDs')
92-
parser.add_argument('tenants')
93-
parser.add_argument('archived')
94-
9565
@admin_required
9666
def get(self, id):
9767
rentalProperty = PropertyModel.find_by_id(id)
@@ -110,37 +80,4 @@ def delete(self, id):
11080

11181
@admin_required
11282
def put(self, id):
113-
data = Properties.parser.parse_args()
114-
rentalProperty = PropertyModel.find_by_id(id)
115-
116-
#variable statements allow for only updated fields to be transmitted
117-
if(data.address):
118-
rentalProperty.address = data.address
119-
120-
if(data.city):
121-
rentalProperty.city = data.city
122-
123-
if(data.name):
124-
rentalProperty.name = data.name
125-
126-
if(data.zipcode):
127-
rentalProperty.zipcode = data.zipcode
128-
129-
if(data.state):
130-
rentalProperty.state = data.state
131-
132-
if (data.unit):
133-
rentalProperty.unit = data.unit
134-
135-
if data.propertyManagerIDs:
136-
rentalProperty.managers = PropertyModel.set_property_managers(data.propertyManagerIDs)
137-
138-
#the reported purpose of this route is toggling the "archived" status
139-
#but an explicit value of "archive" in the request body will override
140-
rentalProperty.archived = not rentalProperty.archived
141-
if(data.archived == True or data.archived == False):
142-
rentalProperty.archived = data.archived
143-
144-
rentalProperty.save_to_db()
145-
146-
return rentalProperty.json()
83+
return PropertyModel.update(schema=PropertySchema, id=id, payload=request.json).json()

schemas/property.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from ma import ma
22
from models.property import PropertyModel
3-
from marshmallow import fields, validates, ValidationError
3+
from models.user import UserModel
4+
from schemas.property_assignment import PropertyAssignSchema
5+
from marshmallow import fields, validates, ValidationError, post_load
46
from utils.time import time_format
57

68

@@ -13,6 +15,21 @@ class Meta:
1315
propertyManagerIDs = fields.List(fields.Integer(), required=True)
1416

1517
@validates("propertyManagerIDs")
16-
def validates_manager_assigned(self, value):
18+
def validates_property_manager_ids(self, value):
1719
if len(value) < 1:
1820
raise ValidationError('manager must be assigned')
21+
22+
payload = [ {'manager_id': value[manager_id]} for manager_id in range(len(value)) ]
23+
PropertyAssignSchema().load(payload, partial=True, many=True)
24+
25+
@validates("name")
26+
def validates_uniqueness_of_name(self, value):
27+
if PropertyModel.find_by_name(value):
28+
raise ValidationError('A property with this name already exists')
29+
30+
@post_load
31+
def make_property_attributes(self, data, **kwargs):
32+
if 'propertyManagerIDs' in data:
33+
data['managers'] = [ UserModel.find(manager) for manager in data['propertyManagerIDs'] ]
34+
del(data['propertyManagerIDs'])
35+
return data

tests/factory_fixtures/property.py

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,25 @@
11
import pytest
22
from models.property import PropertyModel
3+
from schemas.property import PropertySchema
34

45
@pytest.fixture
5-
def property_attributes(faker):
6-
def _property_attributes(archived=False, pm=None):
6+
def property_attributes(faker, create_property_manager):
7+
def _property_attributes(archived=False, manager_ids=[create_property_manager().id]):
78
return {
89
'name': faker.unique.name(),
910
'address': faker.address(),
1011
'city': faker.city(),
1112
'unit': faker.building_number(),
12-
'state': faker.state() ,
13+
'state': faker.state(),
1314
'zipcode': faker.postcode(),
14-
'propertyManagerIDs': [pm.id] if pm and pm.id else [],
1515
'archived': archived,
16+
'propertyManagerIDs': manager_ids
1617
}
1718
yield _property_attributes
1819

1920
@pytest.fixture
20-
def create_property(property_attributes, create_property_manager):
21+
def create_property(property_attributes):
2122
def _create_property():
22-
property = PropertyModel(**property_attributes(
23-
pm=create_property_manager(),
24-
archived=False,
25-
))
26-
property.save_to_db()
23+
property = PropertyModel.create(payload=property_attributes(), schema=PropertySchema)
2724
return property
2825
yield _create_property
29-

0 commit comments

Comments
 (0)