Roundup Tracker - Issues

Message8170

Author rouilj
Recipients rouilj, schlatterbeck
Date 2024-10-27.17:13:16
Message-id <20241027171308.7ADED6A01A3@pe15.cs.umb.edu>
In-reply-to <20241027064407.uzxiynqywsbcypby@runtux.com>
Hi Ralf:

In message <20241027064407.uzxiynqywsbcypby@runtux.com>,
Ralf Schlatterbeck writes:
>Proposal for examples:
>We already have a check function on query (at least in the classic
>template) that permits users to see their own and public (private_for
>empty) queries.
>
>def view_query(db, userid, itemid):
>    private_for = db.query.get(itemid, 'private_for')
>    if not private_for:
>        return True
>    return userid == private_for
>
>Augmenting this with a filter function:
>
>    def filter_query(db, userid, klass):
>        return [dict(filterspec = dict(private_for=['-1', userid]))]

Would:

   return [{"filterspec": {"private_for": ['-1', userid]}}]

be the same? If so we should probably have an example without the use
of dict() if possible. IIRC dict is slower than the definition using
{} (I can't remember the name for the {}'ed definition.  Also I think
the static definition is more familiar to users/admins as well.

In the 'private_for' list, I assume -1 means unset and that items in
the list are or'ed together.

We also need a reference link to the filter syntax. References.txt has
a reference for filter in the hyperdb wrapper class. Is that good
enough? I have always found it a bit difficult to understand and there
aren't a lot of great examples that show the input filter dictionary
and describes how it gets applied. IIRC you had a similar issue a
while back and added some more documentation.

I also have an uncommited section in my user_guide.txt titled:

  Advanced Searching with Property Expressions

that talks about using RPN notation in the URL for filtering. I
haven't committed it because I haven't verified all the examples I
mention. IIRC I wrote this before 2.4.0 was released and didn't commit
it then because one of my examples failed. Also I am not sure that
this location would be proper doc for the filterspec syntax.

>Now if we also want to check if the user is the creator of a query and
>permit access we would modify these to::
>
>    def view_query(db, userid, itemid):
>        q = db.query.getnode(itemid)
>        if not q.private_for or userid == q.private_for:
>            return True
>        if userid == q.creator:
>            return True
>
>    def filter_query(db, userid, klass):

>        return [f1, f2]
>
>Note how we need a list with more than one entry here to account for the
>OR-condition.

Understood.

Do we need AND-condition or NOT-condition examples as well?

I assume (a nonsense) AND is:

   f1 = dict(filterspec = dict(private_for=['-1', userid],
                               dict(creator=userid))

I still haven't traced through the code enough to understand how these
end up being applied at the database level. What do the WHERE clauses
look like when the filter is pushed down to the SQL level?

>Another example would be the following: Consider we have a class
>"organization". A user has a link to organization and the issue has a
>link to organization. Users can see only issues of their own
>organisation.
>
>A check function would be::
>
>    def view_issue(db, userid, itemid):
>        user  = db.user.getnode(userid)
>        if not user.organisation:
>            return False
>        issue = db.issue.getnode(itemid)
>        if user.organisation == issue.organisation:
>            return True
>
>The corresponding filter function::
>
>    def filter_issue(db, userid, klass):
>        user = db.user.getnode(userid)
>        if not user.organisation:
>            return []
>        return [dict(filterspec = dict(organisation=user.organisation))]
>
>Note how the filter fails early by returning an empty list of filter
>arguments when the user has no organisation.
>

The filter function here exactly duplicates the check function
correct? If so, does this make the check function redundant? Can the
permission be defined with only the filter function and no check
function?

Also how would that be modified to include people with an admin role?
Are filter's ignored if the user is an Admin?

I view adding 'filter' to permissions as the equivalent to the
hyperdb's filter_sql() method. Do you agree?  (Side note filter_sql is
missing examples.)

If we are using 'filter' on a non-sql database (dbm, or future mongo
etc.), how is the 'filter' applied? You said that the filter_function
could be debugged on a dbm style database.

>I think this documents most of the use-cases.
>Note that so far I've never needed the 'klass' argument to the filter
>function. It might be needed when a filter applies to more than one
>class, though.

I assume this would happen only if the value you are checking is
equivalent in the two classes but has different names.

Consider a filter checking to see if the owner of the item is the
current owner.  However you have help desk people creating issues and
users. So the creator property is a random help desk person, not the
actual creator. So you have a user_id property added to the user class
and a requestr_id property added to the issue class to record the id
for the actual person.

So you would generate a different filter against a different field
based on the klass.

Is this an example when applying a filter to multiple classes?

>Let me know what you think!

This looks very promising.

Thanks for tackling it.
History
Date User Action Args
2024-10-27 17:13:17rouiljsetrecipients: + rouilj, schlatterbeck
2024-10-27 17:13:17rouiljlinkissue2551330 messages
2024-10-27 17:13:16rouiljcreate