diff --git a/ordr3/models.py b/ordr3/models.py index f8b664b..cfad789 100644 --- a/ordr3/models.py +++ b/ordr3/models.py @@ -1,6 +1,8 @@ import enum from datetime import datetime, timedelta +from collections import namedtuple +VendorAggregate = namedtuple("VendorAggregate", ["name", "terms"]) @enum.unique class OrderStatus(enum.Enum): @@ -158,7 +160,6 @@ class Vendor(Model): self.term = term self.name = name - class User(Model): id = None diff --git a/ordr3/repo.py b/ordr3/repo.py index a0b7861..acf8207 100644 --- a/ordr3/repo.py +++ b/ordr3/repo.py @@ -64,6 +64,10 @@ class AbstractOrderRepository(abc.ABC): def search_vendor(self, reference): """ search for a vendor by its canonical name """ + @abc.abstractmethod + def get_vendor_aggregates(self, reference): + """ list a all canonical names of vendors """ + @abc.abstractmethod def add_reset_token(self, token): """ add an password reset token """ @@ -190,14 +194,19 @@ class SqlAlchemyRepository(AbstractOrderRepository): def search_vendor(self, reference): """ search for a vendor by its canonical name """ - vendor = ( + return ( self.session.query(models.Vendor) .filter_by(term=reference) .one_or_none() ) - if vendor is None: - return None - return vendor.name + + def get_vendor_aggregates(self, reference): + """ list a all canonical names of vendors """ + vendors = self.session.query(models.Vendor).filter_by(name=reference).all() + if not vendors: + raise RepoItemNotFound + terms = sorted((v.term for v in vendors), key=lambda x:x.lower()) + return models.VendorAggregate(vendors[0].name, terms) def add_reset_token(self, token): """ add an password reset token """ diff --git a/ordr3/resources.py b/ordr3/resources.py index 0fa60e0..50519cc 100644 --- a/ordr3/resources.py +++ b/ordr3/resources.py @@ -82,7 +82,6 @@ class Order(BaseResource): @classmethod def from_model(cls, model, parent): - """ initializes a resource from an SQLalchemy object """ return cls(model.id, parent, model) @@ -106,6 +105,37 @@ class OrderList(BaseResource): raise KeyError from e +class Vendor(BaseResource): + def __acl__(self): + """ access controll list """ + acl = [ + (Allow, "role:admin", "view"), + (Allow, "role:admin", "edit"), + DENY_ALL, + ] + return acl + + @classmethod + def from_model(cls, model, parent): + """ initializes a resource from an model object """ + print(model) + return cls(model.name, parent, model) + + +class VendorList(BaseResource): + def __acl__(self): + """ access controll list """ + return [(Allow, "role:admin", "view"), DENY_ALL] + + def __getitem__(self, key): + """ returns child resources """ + try: + aggregagtes = self.request.repo.get_vendor_aggregates(key) + return Vendor.from_model(aggregagtes, self) + except StopIteration as e: + raise KeyError from e + + class Root(BaseResource): """ Root resource """ @@ -115,6 +145,7 @@ class Root(BaseResource): nodes = { "users": UserList, "orders": OrderList, + "vendors": VendorList, } def __init__(self, request): @@ -131,6 +162,7 @@ class Root(BaseResource): ] + def includeme(config): """ Initialize the resources for traversal in a Pyramid app. diff --git a/ordr3/services.py b/ordr3/services.py index 2cac71a..59247ce 100644 --- a/ordr3/services.py +++ b/ordr3/services.py @@ -112,7 +112,7 @@ def check_vendor_name(repo, to_check): if vendor is None: return CheckVendorResult(canonical_name, False) else: - return CheckVendorResult(vendor, True) + return CheckVendorResult(vendor.name, True) def set_new_password(user, password, event_queue): diff --git a/ordr3/templates/orders/list_content.jinja2 b/ordr3/templates/orders/list_content.jinja2 index 099a943..d512e51 100644 --- a/ordr3/templates/orders/list_content.jinja2 +++ b/ordr3/templates/orders/list_content.jinja2 @@ -32,7 +32,7 @@ {{ macros.status_label(order.model.status) }}