Skip to content

Commit

Permalink
Merge pull request #219 from pennlabs/rookie-subletting
Browse files Browse the repository at this point in the history
Create Subletting
  • Loading branch information
dr-Jess authored Nov 12, 2023
2 parents ad83f70 + 90eac30 commit 01d1035
Show file tree
Hide file tree
Showing 18 changed files with 1,574 additions and 373 deletions.
1 change: 1 addition & 0 deletions backend/Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ django-labs-accounts = "*"
django-debug-toolbar = "*"
django-runtime-options = "*"
django-storages = "*"
django-phonenumber-field = {extras = ["phonenumberslite"],version = "*"}
pillow = "*"
boto3 = "*"
apns2 = "*"
Expand Down
767 changes: 394 additions & 373 deletions backend/Pipfile.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions backend/pennmobile/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@
"gsr_booking",
"portal",
"options.apps.OptionsConfig",
"sublet",
"phonenumber_field",
]

MIDDLEWARE = [
Expand Down
1 change: 1 addition & 0 deletions backend/pennmobile/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
),
path("dining/", include("dining.urls")),
path("penndata/", include("penndata.urls")),
path("sublet/", include("sublet.urls")),
]

urlpatterns = [
Expand Down
Empty file added backend/sublet/__init__.py
Empty file.
19 changes: 19 additions & 0 deletions backend/sublet/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from django.contrib import admin
from django.utils.html import mark_safe

from sublet.models import Amenity, Offer, Sublet, SubletImage


class SubletAdmin(admin.ModelAdmin):
def image_tag(self, instance):
images = ['<img src="%s" height="150" />' for image in instance.images.all()]
return mark_safe("<br>".join(images))

image_tag.short_description = "Sublet Images"
readonly_fields = ("image_tag",)


admin.site.register(Offer)
admin.site.register(Amenity)
admin.site.register(Sublet, SubletAdmin)
admin.site.register(SubletImage)
6 changes: 6 additions & 0 deletions backend/sublet/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class SublettingConfig(AppConfig):
name = "sublet"
verbose_name = "Subletting"
129 changes: 129 additions & 0 deletions backend/sublet/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# Generated by Django 3.2.23 on 2023-11-12 20:33

import django.db.models.deletion
import phonenumber_field.modelfields
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

initial = True

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.CreateModel(
name="Amenity",
fields=[("name", models.CharField(max_length=255, primary_key=True, serialize=False)),],
),
migrations.CreateModel(
name="Offer",
fields=[
(
"id",
models.AutoField(
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
),
),
("email", models.EmailField(blank=True, max_length=255, null=True)),
(
"phone_number",
phonenumber_field.modelfields.PhoneNumberField(
blank=True, max_length=128, null=True, region=None
),
),
("message", models.CharField(blank=True, max_length=255)),
("created_date", models.DateTimeField(auto_now_add=True)),
],
),
migrations.CreateModel(
name="Sublet",
fields=[
(
"id",
models.AutoField(
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
),
),
("title", models.CharField(max_length=255)),
("address", models.CharField(blank=True, max_length=255, null=True)),
("beds", models.IntegerField(blank=True, null=True)),
("baths", models.IntegerField(blank=True, null=True)),
("description", models.TextField(blank=True, null=True)),
("external_link", models.URLField(max_length=255)),
("min_price", models.IntegerField()),
("max_price", models.IntegerField()),
("created_at", models.DateTimeField(auto_now_add=True)),
("expires_at", models.DateTimeField()),
("start_date", models.DateField()),
("end_date", models.DateField()),
("amenities", models.ManyToManyField(blank=True, to="sublet.Amenity")),
(
"favorites",
models.ManyToManyField(
blank=True, related_name="sublets_favorited", to=settings.AUTH_USER_MODEL
),
),
(
"sublettees",
models.ManyToManyField(
blank=True,
related_name="sublets_offered",
through="sublet.Offer",
to=settings.AUTH_USER_MODEL,
),
),
(
"subletter",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL
),
),
],
),
migrations.CreateModel(
name="SubletImage",
fields=[
(
"id",
models.AutoField(
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
),
),
("image", models.ImageField(upload_to="sublet/images")),
(
"sublet",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="images",
to="sublet.sublet",
),
),
],
),
migrations.AddField(
model_name="offer",
name="sublet",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="offers",
to="sublet.sublet",
),
),
migrations.AddField(
model_name="offer",
name="user",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="offers_made",
to=settings.AUTH_USER_MODEL,
),
),
migrations.AddConstraint(
model_name="offer",
constraint=models.UniqueConstraint(fields=("user", "sublet"), name="unique_offer"),
),
]
Empty file.
58 changes: 58 additions & 0 deletions backend/sublet/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from django.contrib.auth import get_user_model
from django.db import models
from phonenumber_field.modelfields import PhoneNumberField


User = get_user_model()


class Offer(models.Model):
class Meta:
constraints = [models.UniqueConstraint(fields=["user", "sublet"], name="unique_offer")]

user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="offers_made")
sublet = models.ForeignKey("Sublet", on_delete=models.CASCADE, related_name="offers")
email = models.EmailField(max_length=255, null=True, blank=True)
phone_number = PhoneNumberField(null=True, blank=True)
message = models.CharField(max_length=255, blank=True)
created_date = models.DateTimeField(auto_now_add=True)

def __str__(self):
return f"Offer for {self.sublet} made by {self.user}"


class Amenity(models.Model):
name = models.CharField(max_length=255, primary_key=True)

def __str__(self):
return self.name


class Sublet(models.Model):
subletter = models.ForeignKey(User, on_delete=models.CASCADE)
sublettees = models.ManyToManyField(
User, through=Offer, related_name="sublets_offered", blank=True
)
favorites = models.ManyToManyField(User, related_name="sublets_favorited", blank=True)
amenities = models.ManyToManyField(Amenity, blank=True)

title = models.CharField(max_length=255)
address = models.CharField(max_length=255, null=True, blank=True)
beds = models.IntegerField(null=True, blank=True)
baths = models.IntegerField(null=True, blank=True)
description = models.TextField(null=True, blank=True)
external_link = models.URLField(max_length=255)
min_price = models.IntegerField()
max_price = models.IntegerField()
created_at = models.DateTimeField(auto_now_add=True)
expires_at = models.DateTimeField()
start_date = models.DateField()
end_date = models.DateField()

def __str__(self):
return f"{self.title} by {self.subletter}"


class SubletImage(models.Model):
sublet = models.ForeignKey(Sublet, on_delete=models.CASCADE, related_name="images")
image = models.ImageField(upload_to="sublet/images")
44 changes: 44 additions & 0 deletions backend/sublet/permissions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from rest_framework import permissions


class IsSuperUser(permissions.BasePermission):
"""
Grants permission if the current user is a superuser.
"""

def has_object_permission(self, request, view, obj):
return request.user.is_superuser

def has_permission(self, request, view):
return request.user.is_superuser


class SubletOwnerPermission(permissions.BasePermission):
"""
Custom permission to allow the owner of a Sublet to edit or delete it.
"""

def has_permission(self, request, view):
return request.user.is_authenticated

def has_object_permission(self, request, view, obj):
# Check if the user is the owner of the Sublet.
if request.method in permissions.SAFE_METHODS:
return True
return obj.subletter == request.user


class OfferOwnerPermission(permissions.BasePermission):
"""
Custom permission to allow owner of an offer to delete it.
"""

def has_permission(self, request, view):
return request.user.is_authenticated

def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
# Check if the user owns the sublet when getting list
return obj.subletter == request.user
# This is redundant, here for safety
return obj.user == request.user
Loading

0 comments on commit 01d1035

Please sign in to comment.