Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions backend/bamboo/blueprints/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
from bamboo.blueprints.command import command
from bamboo.blueprints.error import error
from bamboo.blueprints.media import media
from bamboo.blueprints.organization import organization
from bamboo.blueprints.page import page
from bamboo.blueprints.partnership import partnership
from bamboo.blueprints.site import site
from bamboo.blueprints.talk import talk

Expand All @@ -21,3 +23,5 @@ def init_app(app: APIFlask) -> None:
app.register_blueprint(page, url_prefix="/api/page")
app.register_blueprint(site, url_prefix="/api/site")
app.register_blueprint(talk, url_prefix="/api/talk")
app.register_blueprint(organization, url_prefix="/api/organization")
app.register_blueprint(partnership, url_prefix="/api/partnership")
55 changes: 55 additions & 0 deletions backend/bamboo/blueprints/organization.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from apiflask import APIBlueprint, abort

from bamboo.database import db
from bamboo.database.models import Media, Organization
from bamboo.schemas.organization import OrganizationIn, OrganizationOut

organization = APIBlueprint("organization ", __name__)


@organization.get("/<int:organization_id>")
@organization.output(OrganizationOut)
def get_organization(organization_id):
return db.get_or_404(Organization, organization_id)


@organization.post("/")
@organization.input(OrganizationIn, location="json")
@organization.output(OrganizationOut)
def create_organization(json_data):
image = db.session.get(Media, json_data.pop("profile_image_id"))
if not image:
abort(404, message="Image not found")
json_data["profile_image"] = image

payload = Organization(**json_data)
db.session.add(payload)
db.session.commit()
return payload


@organization.patch("/<int:organization_id>")
@organization.input(OrganizationIn(partial=True), location="json")
@organization.output(OrganizationOut)
def update_organization(organization_id, json_data):
payload = db.get_or_404(Organization, organization_id)

if "profile_image_id" in json_data:
image = db.session.get(Media, json_data.pop("profile_image_id"))
if not image:
abort(404, message="Image not found")
json_data["profile_image"] = image

for attr, value in json_data.items():
setattr(payload, attr, value)
db.session.commit()
return payload


@organization.delete("/<int:organization_id>")
@organization.output({}, status_code=204)
def delete_organization(organization_id):
payload = db.get_or_404(Organization, organization_id)
db.session.delete(payload)
db.session.commit()
return ""
88 changes: 88 additions & 0 deletions backend/bamboo/blueprints/partnership.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
from apiflask import APIBlueprint, abort

from bamboo.database import db
from bamboo.database.models import City, Organization, Partnership
from bamboo.schemas.partnership import (
PartnershipByCityIn,
PartnershipByPrimaryIn,
PartnershipIn,
PartnershipOut,
)

partnership = APIBlueprint("partnership ", __name__)


@partnership.get("/")
@partnership.input(PartnershipByPrimaryIn, location="query")
@partnership.output(PartnershipOut)
def get_partnership(query_data):
return db.get_or_404(Partnership, query_data)


@partnership.get("/list")
@partnership.input(PartnershipByCityIn, location="query")
@partnership.output(PartnershipOut(many=True))
def get_partnership_query(query_data):
query = db.select(Partnership)
if "city_id" in query_data:
city = db.session.get(City, query_data.pop("city_id"))
if not city:
return []
query = query.filter_by(city=city)
return db.session.execute(query).scalars()


@partnership.post("/")
@partnership.input(PartnershipIn, location="json")
@partnership.output(PartnershipOut)
def create_partnership(json_data):
city = db.session.get(City, json_data.pop("city_id"))
if not city:
abort(404, message="City not found")
json_data["city"] = city

organization = db.session.get(Organization, json_data.pop("organization_id"))
if not organization:
abort(404, message="Organization not found")
json_data["organization"] = organization

payload = Partnership(**json_data)
db.session.add(payload)
db.session.commit()
return payload


@partnership.patch("/")
@partnership.input(PartnershipIn(partial=True), location="json")
@partnership.output(PartnershipOut)
def update_partnership(json_data):
if "city_id" not in json_data or "organization_id" not in json_data:
abort(422, message="Missing city_id or organization_id")
payload = db.get_or_404(
Partnership,
{
"city_id": json_data["city_id"],
"organization_id": json_data["organization_id"],
},
)

if "category" in json_data:
payload.category = json_data["category"]
db.session.commit()
return payload


@partnership.delete("/")
@partnership.input(PartnershipIn, location="query")
@partnership.output({}, status_code=204)
def delete_partnership(query_data):
payload = db.get_or_404(
Partnership,
{
"city_id": query_data["city_id"],
"organization_id": query_data["organization_id"],
},
)
db.session.delete(payload)
db.session.commit()
return ""
17 changes: 17 additions & 0 deletions backend/bamboo/schemas/organization.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from apiflask import Schema
from apiflask.fields import DateTime, Integer, String


class OrganizationIn(Schema):
name = String(required=True)
url = String()
profile_image_id = Integer(required=True)


class OrganizationOut(Schema):
name = String()
url = String()
profile_image_id = Integer()
id = Integer()
created_at = DateTime()
updated_at = DateTime()
25 changes: 25 additions & 0 deletions backend/bamboo/schemas/partnership.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from apiflask import Schema
from apiflask.fields import DateTime, Integer, String


class PartnershipIn(Schema):
city_id = Integer(required=True)
organization_id = Integer(required=True)
category = String()


class PartnershipByCityIn(Schema):
city_id = Integer()


class PartnershipByPrimaryIn(Schema):
city_id = Integer(required=True)
organization_id = Integer(required=True)


class PartnershipOut(Schema):
city_id = Integer()
organization_id = Integer()
category = String()
created_at = DateTime()
updated_at = DateTime()
28 changes: 28 additions & 0 deletions backend/tests/models/test_organization.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from bamboo.database import db, models


def test_organization(client):
profile = models.Media.from_file("test.png")
organization = models.Organization(
name="code-kitchen", url="https://codekitchen.community", profile_image=profile
)
db.session.add_all([profile, organization])
db.session.commit()

organ = db.session.scalars(db.select(models.Organization)).all()
assert len(organ) == 1
assert organ[0].name == "code-kitchen"
assert organ[0].url == "https://codekitchen.community"
assert organ[0].profile_image.path == "test.png"
assert organ[0].profile_image.content_type == "image/png"

organization.name = "test"
db.session.commit()
organ = db.session.scalars(db.select(models.Organization)).all()
assert len(organ) == 1
assert organ[0].name == "test"

db.session.delete(organization)
db.session.commit()
organ = db.session.scalars(db.select(models.Organization)).all()
assert len(organ) == 0
28 changes: 28 additions & 0 deletions backend/tests/models/test_partnership.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from bamboo.database import db, models


def test_partnership(client):
profile = models.Media.from_file("test.png")
organization = models.Organization(
name="code-kitchen", url="https://codekitchen.community", profile_image=profile
)
site = models.Site(name="Test site", config={})
city = models.City(name="Test city", site=site)
profile = models.Media.from_file("test.png")
user = models.User(name="staff", profile_image=profile)
city.staffs.add(models.Staff(staff=user, category="supporter"))
db.session.add_all([profile, organization, city])
partnership = models.Partnership(city=city, organization=organization, category="supporter")
db.session.add_all([partnership])
db.session.commit()

partner = db.session.scalars(db.select(models.Partnership)).all()
assert len(partner) == 1
assert partner[0].city.name == "Test city"
assert partner[0].organization.name == "code-kitchen"
assert partner[0].category == "supporter"

db.session.delete(partnership)
db.session.commit()
organ = db.session.scalars(db.select(models.Partnership)).all()
assert len(organ) == 0
64 changes: 64 additions & 0 deletions backend/tests/test_organization.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
from bamboo.database import db, models


def test_create_organization(client):
response = client.post("/api/organization/", json={})

assert response.status_code == 422

assert response.json["detail"]["json"]["name"][0] == "Missing data for required field."
assert (
response.json["detail"]["json"]["profile_image_id"][0] == "Missing data for required field."
)

db.session.add(models.Media.from_file("test.png"))
db.session.commit()
response = client.post(
"/api/organization/",
json={
"name": "code-kitchen",
"url": "https://codekitchen.community",
"profile_image_id": 1,
},
)
assert response.status_code == 200
assert response.json["name"] == "code-kitchen"
assert response.json["url"] == "https://codekitchen.community"
assert response.json["profile_image_id"] == 1


def test_update_organization(client):
test_create_organization(client)
response = client.patch("/api/organization/1", json={"name": "test"})
assert response.status_code == 200
assert response.json["name"] == "test"

response = client.patch("/api/organization/1", json={"profile_image_id": 2})
assert response.status_code == 404

image1 = models.Media.from_file("test.png")
db.session.add_all([image1])

response = client.patch("/api/organization/1", json={"profile_image_id": 2})
assert response.status_code == 200


def test_delete_organization(client):
response = client.delete("/api/organization/999")
assert response.status_code == 404

test_create_organization(client)
response = client.delete("/api/organization/1")
assert response.status_code == 204


def test_get_organization(client):
response = client.get("/api/organization/1")
assert response.status_code == 404

test_create_organization(client)
response = client.get("/api/organization/1")
assert response.status_code == 200
assert response.json["name"] == "code-kitchen"
assert response.json["url"] == "https://codekitchen.community"
assert response.json["profile_image_id"] == 1
Loading