_eq permission value against ID in different table? - postgresql

I'm setting up some permissions in hasura, I have an 'assigned' table which maps an assigned item to a user, I require the user to be able to only access items they have been assigned. I figured the best way to do this was with the _exists operator where I have:
{"_exists":{"_table":{"name":"assigned_item","schema":"public"},"_where":{"_and":[{"userid":{"_eq":"X-Hasura-User-Id"}},{"feed_item_id":{"_eq":"XXX"}}]}}
My issue comes into play with the last _eq: XXX - I need for it to equal the value from the item table.
The permission is being created against the assigned item.

Assuming your assigned_item table has userid and feed_item_id .. your permissions should be:
on the assigned_item table, just add the permission: userid _eq X-Hasura-User-Id as in "A user can see all their assigned items".
on the feed_items? table, use the relationship to reach the user_id through the assigned_item table. Assuming the relationship on feed_items is called say "assigned_users", then the permission is: feed_items > assigned_users > user_id _eq X-Hasura-User-Id

Related

Track history of ManyToMany Relationship table with extra fields

I have a many to many relationship table (named UserLabel) in the postgres db with some extra field. I want to be able to track the history of changes to this many to many table. I came up with the following structure. I'd like to know if there's any better way of implementing it
User
id
Label
id
UserLabel
id
user_id
label_id
label_info (jsonb)
is_deleted (true or false)
UserLabel can contain more than one record with same user_id and label_id but with different label_info. At any point of time, if I want to query for all the labels for a given user I can do that using this table. Now, updates could occur on this table on label_id or label_info or is_deleted fields. I want to be able to know at any given point of time, what were the labels and label info of a user. For this, I'm using the below table.
UserLabelEvent
id
user_label_id
user_id
label_id
label_info
change_type (value will be one of (create, update, delete))
created_timestamp
If I want to check the user labels for any user at any time, I just have to query on user_id and created_timestamp and order the records by created_timestamp and loop over the records to construct the user labels at any given time.
The problems in my current approach:
By default, anyone seeing at the schema of UserLabel table feels like there cannot be more than one record with same user_id and same label_id.
By looking at the UserLabelEvent, it's not obvious to understand how that table is working.
I need to do some post processing to find out the user labels at any given time. By post processing, I mean, loop over the query results and construct the user labels.
Please do suggest any other problems you find with this approach. I will update the post with new inputs.

How do I set my hasura permission to only see the rows of my table corresponding to a user?

Here's the thing. I have the 3 tables depicted here:
People on my application can place orders. Then, I want
a user with rex permission to see all the orders table's rows
a user with delivery permission to only see the rows of the orders table that have the zip column set to the delivery user's zip
From the orders table, I can get for each order a zip. With the table zip_user, I can get a user_id out of a zip. Out of that user_id, I can get the delivery user from the users table.
While it is trivial to get the rex to see all of the orders table, I have not yet been able to configure the permissions for the delivery user. What do I need to do?
In other words, given the user performing a select on the orders table has x-hasura-user-id set to some user id and x-hasura-role set to delivery, how does that user get only the rows from the orders table that match with the zips associated with that user's user_id?
Hasura has the concept of relations. If you have foreign keys, it makes the relations automatically, if not you can make them yourself in the UI. Once the relationships have been set up, you will be able to set deep permissions, so on the orders table, you'll be able to use users.id.
Start here: https://hasura.io/docs/1.0/graphql/manual/schema/relationships/index.html

Filter and display database audit / changelog (activity stream)

I'm developing an application with SQLAlchemy and PostgreSQL. Users of the system modify data in 8 or so tables. Consider this contrived example schema:
I want to add visible logging to the system to record what has changed, but not necessarily how it has changed. For example: "User A modified product Foo", "User A added user B" or "User C purchased product Bar". So basically I want to store:
Who made the change
A message describing the change
Enough information to reference the object that changed, e.g. the product_id and customer_id when an order is placed, so the user can click through to that entity
I want to show each user a list of recent and relevant changes when they log in to the application (a bit like the main timeline in Facebook etc). And I want to store subscriptions, so that users can subscribe to changes, e.g. "tell me when product X is modified", or "tell me when any products in store S are modified".
I have seen the audit trigger recipe, but I'm not sure it's what I want. That audit trigger might do a good job of recording changes, but how can I quickly filter it to show recent, relevant changes to the user? Options that I'm considering:
Have one column per ID type in the log and subscription tables, with an index on each column
Use full text search, combining the ID types as a tsvector
Use an hstore or json column for the IDs, and index the contents somehow
Store references as URIs (strings) without an index, and walk over the logs in reverse date order, using application logic to filter by URI
Any insights appreciated :)
Edit It seems what I'm talking about it an activity stream. The suggestion in this answer to filter by time first is sounding pretty good.
Since the objects all use uuid for the id field, I think I'll create the activity table like this:
Have a generic reference to the target object, with a uuid column with no foreign key, and an enum column specifying the type of object it refers to.
Have an array column that stores generic uuids (maybe as text[]) of the target object and its parents (e.g. parent categories, store and organisation), and search the array for marching subscriptions. That way a subscription for a parent category can match a child in one step (denormalised).
Put a btree index on the date column, and (maybe) a GIN index on the array UUID column.
I'll probably filter by time first to reduce the amount of searching required. Later, if needed, I'll look at using GIN to index the array column (this partially answers my question "Is there a trick for indexing an hstore in a flexible way?")
Update this is working well. The SQL to fetch a timeline looks something like this:
SELECT *
FROM (
SELECT DISTINCT ON (activity.created, activity.id)
*
FROM activity
LEFT OUTER JOIN unnest(activity.object_ref) WITH ORDINALITY AS act_ref
ON true
LEFT OUTER JOIN subscription
ON subscription.object_id = act_ref.act_ref
WHERE activity.created BETWEEN :lower_date AND :upper_date
AND subscription.user_id = :user_id
ORDER BY activity.created DESC,
activity.id,
act_ref.ordinality DESC
) AS sub
WHERE sub.subscribed = true;
Joining with unnest(...) WITH ORDINALITY, ordering by ordinality, and selecting distinct on the activity ID filters out activities that have been unsubscribed from at a deeper level. If you don't need to do that, then you could avoid the unnest and just use the array containment #> operator, and no subquery:
SELECT *
FROM activity
JOIN subscription ON activity.object_ref #> subscription.object_id
WHERE subscription.user_id = :user_id
AND activity.created BETWEEN :lower_date AND :upper_date
ORDER BY activity.created DESC;
You could also join with the other object tables to get the object titles - but instead, I decided to add a title column to the activity table. This is denormalised, but it doesn't require a complex join with many tables, and it tolerates objects being deleted (which might be the action that triggered the activity logging).

Is it possible to restrict access to attributes or items of a table in MongoDB?

I want to restrict access to a table using MongoDB like I do in DynamoDB: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/FGAC_DDB.html
I mean that if I have a employee table that stores the NAME and INCOME, I want a role to restrict access to the INCOME attribute for some users. Also, I want another role that the user will be able to see the NAME and INCOME, but only if it matches a specific condition.
It is not clear if this is possible reading the official MongoDB documentation: http://docs.mongodb.org/manual/reference/built-in-roles/

Read only logic on the basis of user logged in to openbravo

I have a requirement in Openbravo 3.0 framework . I have two user one is HR and the other is employee . Their is a checkbox in user window called HR USER .. In my window I need to write a read only logic so that when HR logins the record has to be editable , and when the employee logins the record has to be non editable,, I know how to do that for normal fields ,, But i am not getting anything about user validation..
In the employee screen i am assigning the user id to that employee.
Please Help
Read Only Logic based on Logged in User:
finding out the ID (primary key) of the User (HR or Employee) using PGAdmin Query tool.
Add read only as shown below.
Read Only Logic based on Logged in Role :
This can be achieved in three steps
creating Auxiliary Input.
finding out the ID (primary key) of the role (HR or Employee)
associating Read Only Logic to the Column.
First of all, we need to add an Auxiliary Input that will make
AD_ROLE_ID of the currently logged in user available to the user
window. Using the System Administrator role navigate to the
Application Dictionary || Setup || Auxiliary Input and create a new
record as shown below:
This will make the #AD_ROLE_ID session variable available to the [user] tab of the HR User window through the #ROLE_ID# variable.
Secondly, you need to find out what the AD_ROLE_ID of the HR role
is. Use the PgAdmin to query the AD_ROLE table and find that out. A
simple query reveals the following:
select ad_role_id, name from ad_role;
ad_role_id | name
----------------------------------+---------------------------
....
1000001 | Admin
SDJFALSDFJKLASJDFKLASDFASLDFJAKLSJ| velmurugan
SDFLAKSDJFLKASJDLFALSDFALDSKFJLAS | Employee
DSKLFJAKLDSJFKLASJFKLADSJFLKAJSDFK| F&B US, Inc. - Admin
....
(38 rows)
The primary key (AD_ROLE_ID) of the HR role is 054A32701D6D4CE6BF4F695DAB23EDB3. This will clearly be different in your case.
With this information, we can now find the HR User field definition
and set its Read Only Logic to
#ROLE_ID#!'054A32701D6D4CE6BF4F695DAB23EDB3' as shown below: