Coverage for postrfp/buyer/api/endpoints/categories.py: 100%
38 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-22 21:34 +0000
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-22 21:34 +0000
1"""
2Use Categories to organize Projects
3"""
5from typing import List
7from sqlalchemy.orm import Session
9from postrfp.shared import fetch
10from postrfp.shared.decorators import http
11from postrfp.shared import serial
12from postrfp.authorisation import perms
13from postrfp.model import Category, User
14from postrfp.model.exc import DuplicateDataProvided
15from postrfp.buyer.api import authorise
18@http
19def get_category(session: Session, user: User, category_id: int) -> serial.Category:
20 """Fetch the Category object for the given ID"""
21 return fetch.category_for_user(session, user, category_id).as_dict()
24@http
25def delete_category(session: Session, user: User, category_id: int):
26 """
27 Delete the category with the given ID.
29 Note that projects belong to this category are __not__ deleted
30 This action requires the user permission 'MANAGE_ORGANISATION'
31 """
32 cat = fetch.category_for_user(session, user, category_id)
33 authorise.check(user, perms.MANAGE_ORGANISATION, target_org=user.organisation)
34 session.delete(cat)
37@http
38def post_category(
39 session: Session, user: User, category_doc: serial.NewCategory
40) -> serial.Category:
41 """
42 Create a new Category belonging to the current user's organisation.
44 Categories with duplicate names are not permitted and receive an HTTP 409 Response
46 @permission MANAGE_CATEGORIES
47 """
48 authorise.check(user, perms.MANAGE_ORGANISATION, target_org=user.organisation)
49 cat_name = category_doc.name
50 existing = (
51 session.query(Category)
52 .filter(Category.organisation == user.organisation)
53 .filter(Category.name == cat_name)
54 .count()
55 )
57 if existing:
58 raise DuplicateDataProvided(f"Category with name '{cat_name}' already exists")
60 cat = Category(
61 name=cat_name,
62 description=category_doc.description,
63 organisation=user.organisation,
64 )
66 session.add(cat)
67 session.flush() # get new ID
68 return serial.Category.model_validate(cat)
71@http
72def put_category(
73 session: Session, user: User, category_id: int, category_doc: serial.NewCategory
74):
75 """
76 Update the name or description for the Category at the given ID
78 This action requires the user permission 'MANAGE_ORGANISATION'
79 """
80 authorise.check(user, perms.MANAGE_ORGANISATION, target_org=user.organisation)
81 cat = fetch.category_for_user(session, user, category_id)
82 cat.name = category_doc.name
83 cat.description = category_doc.description
86@http
87def get_categories(session: Session, user: User) -> List[serial.Category]:
88 """Fetch an array of all Category objects for the user's organisation"""
89 q = (
90 session.query(Category)
91 .filter(Category.organisation == user.organisation)
92 .order_by(Category.name)
93 )
94 return [c.as_dict() for c in q]