Relationship with two APIs (nodejs, angular, express, mysql) - javascript

I am a beginner in angular / node and I have a question that maybe can be simple (I believe) ...
I was following the "Tour of Heroes" tutorial and started to wonder if it would be possible to have a type of "Contract"
Contract would receive the data of the api Hero (id, name ...) and also data of another api "Company" (id, name, location ...) and then join everything in a called api "Contract".
Then in that case I could list "Contract ID" or "contract number", and see the information (which company, which hero, that kind of thing)
Is it possible to do this with node, angular and mysql? if it is ... Could you show me some example or tutorial to follow?
Thank you!

That is possible and easy, you just need a few things set up:
Your db needs a contract table (assuming you want a many to many relationship between heroes and companies) where you set foreign keys to the hero_id and the company_id.
You need a new endpoint in your server that receives the contractId as a parameter and then you can do a request to your mysql db that uses your contract table to join the company to the hero, i.e.
SELECT * FROM hero AS h
JOIN contract AS cont ON h.id = cont.hero_id
JOIN company AS comp ON comp.id = cont.company_id
WHERE cont.id = ? ;
(replace the ? with the contract id you receive from the endpoint, ideally using prepared statements for mysql or a similar solution like the one mysqljs provides)
Angular will just need to call the new endpoint with a contractId parameter and you should receive the data if it exists.

Related

Query the last record in supabase?

How to check the last record of a user in supabase. I would only need by means of the user ID to find his last record "date" in a descending way
I have something like the following, but this would just sort the table and I really don't want to bring it all just the most recent dates. I am working on this in nodejs with express and I am using the #supabase/supabase-js library for auth with supabase
Does anyone know how?
const { data, error } = await supabase.from('activity-historic-tracked').select('*').in('user_id', user_ids).order('date', { ascending: false })
I made the query in supabase using sql with DISTINC ON to return only different values because I only want to list the different values and not bring repeated values and at the end ordering them descendingly
select distinct on (user_id) user_id, date
from "activity-historic-tracked"
order by user_id, date desc;
According to what I was reading in this question rpc function, doing something like this could be done using views or supabase stored procedures, but how is it done?
Please help me
As mentioned in the other SO answer you linked, you can create a view or a rpc function. To create a view you would use the SQL editor in the Supabase Dashboard with the following:
CREATE VIEW view_name AS
SELECT DISTINCT on (user_id) user_id, date
FROM "activity-historic-tracked"
ORDER BY user_id, date DESC;
And now you would use this with the supabase-js library just like you would with a normal table.
await supabase.from('view_name').select('*')
If you were to go the .rpc function route, you would call it via that method on the supabase-js library.

BigQuery similarity to "signed urls"

I have the following use case in BigQuery:
A non-trusted user will be querying a BigQuery table. Let's say the query is SELECT * FROM [bigquery.table123].
The query will return a large amount of data, let's say 200MB, which will then be displayed in the user's browser.
Our goal is to provide the most efficient way to get the 200MB data into the user's browser (and the worst way seems to do two trips instead of one -- from BQ to our server and then (compressed) to the client). I think the solution for this would probably be to enable the end (non-trusted) user to get something like a "signed-url" to perform the query directly from their browser to BigQuery. The flow would then be like this:
User issues query to our backend.
Authentication is done and a signed url is generated and passed back into javascript.
The client then sends the signed url and the data is loaded directly into the browser.
Only that exact query that has been authorized may be performed, and no other queries could be done (for example, if the client copied any tokens from the javascript)
I would never, ever want the end user to know the ProjectId or Table Name(s) that they are querying.
Is something like this possible to do in BigQuery? Here is an example of a similar need in Cloud Storage. Here is an example of an authenticated/trusted user doing this in browser: https://github.com/googleapis/nodejs-bigquery/blob/master/samples/browseRows.js or . https://stackoverflow.com/a/11509425/651174, but is there a way to do this in-browser for a non-trusted user?
Below is an option that involves two levels of authorized views. This allows to shield not only underlying data from end user - but also hides what exactly data is being used
Let's assume data is in DatasetA. Below steps explain the logic
Create InternalView in DatasetB - this one will target real data from DatasetA.
Make InternalView as Authorized View for DatasetA
Create PublicView in DatasetC - this one will target InternalView
Make PublicView as Authorized View for DatasetB
Give users read access to DatasetC
Users will be ale to run PublicView which will actually be running PrivateView against readl data.
Meantime, users will not be able to see the definition of PrivateView thus will never know ProjectId or Table Name(s) that they are querying, etc.
Note: this does not address how we'd prevent users from being able to issue queries that we haven't pre-authorized? part of your question but I am adding my answer as you asked me to do
Meantime - at least theoretically - you can embed some logic into your PrivateView, which will be querying some internal metatable with info which user and when allowed to get result. Assuming that such meta-table will be managed by your backend based on authentication/token or whatever else you have in mind
Below is simplified and brief outline of that approach
#standardSQL
WITH `projectA.datasetA.table` AS (
SELECT 'data1' col UNION ALL
SELECT 'data2' UNION ALL
SELECT 'data3'
), `projectA.datasetA.applicationPermissions` AS (
SELECT 'user1#gmail.com' user UNION ALL
SELECT 'user2#gmail.com'
), `projectA.datasetB.privateView` AS (
SELECT d.*
FROM `projectA.datasetA.table` d
CROSS JOIN `projectA.datasetA.applicationPermissions` p
WHERE LOWER(user) = LOWER(SESSION_USER())
), `projectA.datasetC.publicView` AS (
SELECT *
FROM `projectA.datasetB.privateView`
)
SELECT *
FROM `projectA.datasetC.publicView`
If user1#gmail.com or user2#gmail.com will run below query
SELECT *
FROM `projectA.datasetC.publicView`
they will get below result
Row col
1 data1
2 data2
3 data3
while if user3#gmail.com will run same very query - result will be
Row col
Query returned zero records.
Obviously, you can extend your meta-table (applicationPermissions) with for example timeframe during which user will be allowed to get result (respective lines to check time conditions will need to be added to projectA.datasetB.privateView )

Get access control list (IAM) of a resource group in Node.js

I am using Node.js to interact with Azure, for example, to create a resource group:
const { ResourceManagementClient } = require('azure-arm-resource');
createResourceGroup(location, groupName) {
const groupParameters = {
location: location,
};
return this.resourceClient.resourceGroups.createOrUpdate(groupName, groupParameters);
}
How can I use these azure-arm modules to retrieve the access control (IAM) list of a resource group?
I mean to this list:
You will need to make use of the Azure Authorization Modules for Node.js
Here is sample code based on Microsoft Docs
Installing Azure Authorization module
npm install azure-arm-authorization
List all role assignments for a specific resource group
const msRestAzure = require('ms-rest-azure');
const authorizationManagement = require('azure-arm-authorization');
const resourceGroup = 'resource-group-name';
const subscriptionId = 'your-subscription-id';
msRestAzure.interactiveLogin().then(credentials => {
const client = new authorizationManagement(credentials, subscriptionId);
client.roleAssignments.listForResourceGroup(resourceGroupName).then(result => {
console.log(result);
});
});
Also on a side note, know that the actual REST API being used for these operations is:
Role Assignments - List For Resource Group
GET https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Authorization/roleAssignments?api-version=2015-07-01
Similar API, which accepts a generic scope (to work with not just resource groups but other resources as well)
Role Assignments - List For Scope
GET https://management.azure.com/{scope}/providers/Microsoft.Authorization/roleAssignments?api-version=2015-07-01
UPDATE (trying to answer queries from comments)
Using the code above to list all role assignments for a specific resource group (or role assignments - list for resource group REST API).. you will be returned a collection of role assignments, like your comments reflect.
I suppose this is what you need based on the screenshot from your question, as you have Role Assignments tab selected and the list is being shown below in Azure Portal.
Now a role assignment in itself is formed by:
A security principal Id (user, group, service principal etc. to whom you're trying to give permissions through a role)
Role Definition Id (identifier for the role which you assigning like contributor, owner or a custom RBAC role for that matter)
Scope (at which this role is assigned, like at subscription level or at a specific resource group or resource level)
This concept is explained in detail and very well here on Microsoft Docs
For your purpose to make sense of the response UUIDs, you will be able to find the list of all role definitions (to know their ID, Name Description etc. using Role Definitions List through node SDK or using Role Definitions - List REST API
Principal ID is the ID of user, group or app service principal.
Scope in your case is the resource group that you're trying to query role assignments for.

enter query string in textfield on webpage, click submit and get query results back

I am looking for a generic way to pass any query string (from any oracle table, NOT hardcoded) from a webpage form/field to database and make the webpage display table/grid of the results. All examples i have seen so far require hardcoding columns/table name upfront in CRUD apps on github. I would like to be able to get results from various tables each with different columns, data types. I dont want the tables/columns hardcoded in the app. I have been using SpringBoot so far to accept any query string in POST req and return results as list of json records but i want to make it more interactive, easy to use for casual users so seeking some examples for simple textfield input and dynamic results grid.
Have a look at Knex.js: https://knexjs.org/
It's a query builder that works with different databases. Here's a little sample from their doc:
var knex = require('knex')({
client: 'oracle'
});
function handleRequest(req, res, next) {
query = knex.select(req.body.columns).from(req.body.table);
console.log(query.toString()); // select "c1", "c2", "c3" from "some_table"
}
// Imagine this was invoked from Express and the body was already parsed.
handleRequest({
body: {
table: 'some_table',
columns: ['c1', 'c2', 'c3']
}
});
As you can see, the inputs are just strings which can come from anywhere, including clients/end-users. Just be careful that the user that's connecting to the database has the appropriate grants (least privilege applies here).

Adding information from another mongodb collection before providing the data via meteor's publish method

What I want to accomplish on http://crowducate.me:
Display the usernames of the course authors (i.e. "owner" of a document).
Current Code:
Meteor.publish 'popularCourses', ->
# find all courses
courses = Course.find({}, {sort: {createdAt: -1}}).fetch()
for course in courses
# find each User by course owner
owner = Meteor.users.findOne({_id: course.owner})
# overwrite the ownerId with the desired username
course.owner = owner.username
return courses
If I turn autopublish on, it works. The image shows the current status (autopublish off). As seen in the image, the author's name is only rendered if the current user is the same as the author.
--
A friend suggested the following:
https://gist.github.com/wiesson/1fd93d77ed9df353b7ab
"The basic idea was to attach the username to the course before providing the data with the publish method. However, as described in Meteor MongoDB find / fetch issues, the publish method should return a curser and not an array of objects.”
Any ideas how to solve that? Putting the owner usernames in an array? If so, how?
P.S.: Sourecode can be found here (currently, has more commits than the deployed version):
https://github.com/Crowducate/crowducate.me
Thanks a lot.
There are a couple of ways you can accomplish this join. A few notes before before we begin:
As I explained in the answer to this question, sorting in the publish function has no affect on the order of documents on the client.
Using the plural form in a collection name is the accepted standard. Course just looks odd when the collection contains courses.
This question is fundamentally about joins, so I'd recommend reading Reactive Joins In Meteor.
Server Transform
The literal answer to your question is to transform the documents on the server like so:
Meteor.publish 'popularCourses', ->
transform = (fields) ->
if fields.owner
username = Meteor.users.findOne(fields.owner)?.username
fields.owner = username
fields
handle = Course.find().observeChanges
added: (id, fields) =>
#added 'course', id, transform fields
changed: (id, fields) =>
#changed 'course', id, transform fields
removed: (id) =>
#removed 'course', id
#ready()
#onStop ->
handle.stop()
Advantages
All of the work is done on the server, so the client can just use owner as if it was a username.
Disadvantages
Using observeChanges is probably more computational work than a simple join deserves.
If you publish courses somewhere else, it's entirely likely that owner will be overwritten when the documents are merged on the client. This can be countered by appending a field like ownerUsername but that would also require a more expensive observe.
This isn't helpful if you actually need the owner id somewhere on the client.
It isn't reactive if the username changes (probably rare but figured I'd point that out).
Non-Reactive Publish + Client Join
You could implement the publish like this:
CoffeeScript
Meteor.publish 'popularCourses', ->
courseCursor = Course.find()
userIds = courseCursor.map (c) -> c.owner
userCursor = Meteor.users.find {_id: $in: userIds}, {fields: username: 1}
[courseCursor, userCursor]
JavaScript
Meteor.publish('popularCourses', function() {
var courseCursor = Course.find();
var userIds = courseCursor.map(function(c) {return c.owner;});
var userCursor = Meteor.users.find(
{_id: {$in: userIds}},
{fields: {username: 1}
});
return [courseCursor, userCursor];
});
Note that I'm being careful to only publish the username and _id from userCursor (you don't want to publish the hashed password and session data by accident). Then you can join the two collections on the client like this:
Template.myTemplate.helpers
courses: ->
Course.find().map (c) ->
c.owner = Meteor.users.findOne(c.owner)?.username
c
Advantages
Computationally light-weight and simple publish function.
Reactive if the username changes.
Disadvantages
Not reactive if the owner changes.
You'll need to do the join on the client. An interesting alternative is to use something like Collection Helpers.
Finally, I'll point out that you can use a package to do a fully reactive join. However, unless the owner (or owner's username) is changing a lot then this is probably overkill.
A simple solution would be to just publish both popularCourses and owners and add the owner to each course on the client (with the exact same code you have written on the publication).

Categories