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) }}
 
- + {% if request.has_permission("edit", order) %} {{ macros.icon("pencil")}} {% elif request.has_permission("view", order) %} diff --git a/ordr3/templates/vendors/list.jinja2 b/ordr3/templates/vendors/list.jinja2 new file mode 100644 index 0000000..2f0c8c1 --- /dev/null +++ b/ordr3/templates/vendors/list.jinja2 @@ -0,0 +1,22 @@ +{% extends "ordr3:templates/layout_full.jinja2" %} + +{% block subtitle %} Manage Vendor Autocorrect {% endblock subtitle %} + + +{% block sidebar %} + +{% endblock sidebar %} + + +{% block content %} + +
+

Vendor Autocorrect List

+ +
+ +{% endblock content %} diff --git a/ordr3/views/root.py b/ordr3/views/root.py index 9cc1d76..2ed218e 100644 --- a/ordr3/views/root.py +++ b/ordr3/views/root.py @@ -9,8 +9,8 @@ from pyramid.view import ( from pyramid.httpexceptions import HTTPFound -@forbidden_view_config() -@notfound_view_config() +#@forbidden_view_config() +#@notfound_view_config() @view_config( context="ordr3:resources.Root", permission="view", ) diff --git a/ordr3/views/vendors.py b/ordr3/views/vendors.py new file mode 100644 index 0000000..b94a0c0 --- /dev/null +++ b/ordr3/views/vendors.py @@ -0,0 +1,20 @@ +import deform +from sqlalchemy import func +from pyramid.csrf import get_csrf_token +from pyramid.view import view_config +from pyramid.httpexceptions import HTTPFound + +from .. import events, models, services, resources + + +@view_config( + context="ordr3:resources.VendorList", + permission="view", + request_method="GET", + renderer="ordr3:templates/vendors/list.jinja2", +) +def vendor_list(context, request): + + vendors = request.repo.session.query(models.Vendor.name).distinct(models.Vendor.name).order_by(func.lower(models.Vendor.name)).all() + + return {"vendors":vendors}