Roundup Tracker - Issues

Issue 2551344

classification
Allow rest endpoints added via interfaces.py to overlay existing endpoints.
Type: behavior Severity: normal
Components: API Versions:
process
Status: new
:
: : rouilj
Priority: :

Created on 2024-05-01 02:54 by rouilj, last changed 2024-05-26 03:01 by rouilj.

Messages
msg8024 Author: [hidden] (rouilj) Date: 2024-05-01 02:54
While developing the replacement classhelper web component, we needed to get a list
of roles defined in the database. The template driven classhelper has a drop down
list of roles that can be used when searching the user class.

To replicate that with the web component classhelper, we needed to get a list
from the rest interface. Because roles are defined as a string property of
user and not a multilink, we can't query /rest/data/roles and get a list of roles.

I tried to fake the /data/roles endpoint in interfaces.py using:

  from roundup.rest import Routing, RestfulInstance, _data_decorator
  class RestfulInstance:

    @Routing.route("/roles", 'GET')
    @Routing.route("/data/roles", 'GET')
    @_data_decorator
    def get_roles(self, input):
        """Return all defined roles. The User class property
           roles is a string but simulate it as a MultiLink
           to an actual Roles class.
        """
        return 200, {"collection": [{"id": rolename, "name": rolename.capitalize()}
                  for rolename in sorted(list(self.db.security.role.keys()))]}


but the default rule mapped to "/data/{:class:}" takes priority and caused /data/roles
to throw an error as there is no roles class.

If I modify rest.py with this patch:

--- a/roundup/rest.py   Tue Apr 30 22:27:57 2024 -0400
+++ b/roundup/rest.py   Tue Apr 30 22:44:33 2024 -0400
@@ -399,7 +399,9 @@

         # find the rule match the path
         # then get handler match the method
-        for path_regex, funcs in cls.__route_map.values():
+        seq = [(path_regex, funcs) for path_regex, funcs
+                in  cls.__route_map.values()]
+        for path_regex, funcs in reversed(seq):
             # use compiled regex to find rule
             match_obj = path_regex.match(path)
             if match_obj:

to reverse the order of application of the roles, my definition of
/data/roles is found first and it works. But the original order
is not deterministic. That makes my patch reversing the order, fragile.

The /roles endpoint does return the roles in the correct shape, but the library methods
used in the web component expect to hit /data/ so this is a bit of a refactor for them.

I have a couple of ideas on how to do this.

  1. have two groups of routes and have interfaces.py call Route.route_first
     that is processed first by the router. If no match is found, you use the
     built in routes.

  2. Allow Routing.route to support an order parameter like registering detectors.

Other ideas?

The web component project ticket: https://github.com/UMB-CS-682-Team-03/tracker/issues/33
msg8062 Author: [hidden] (rouilj) Date: 2024-05-26 03:01
Adding a command that can be called from extensions to add a new endpoint would be a
good idea as well. Remove the need to use interfaces.py.
Compare to instance.registerUtil or instance.registerAction.
History
Date User Action Args
2024-05-26 03:01:58rouiljsetmessages: + msg8062
title: Allow rest endpoints added via interfaces.py to overly existing endpoints. -> Allow rest endpoints added via interfaces.py to overlay existing endpoints.
2024-05-01 02:54:30rouiljcreate