Access input in GraphQL Prisma Directive - prisma

I have a use case where in I want to access query parameter/arguments in the directive. Following is the schema.
user(where: UserWhereUniqueInput!): User #isAuthenticated
Query that is fired from playground
user(where:{id: "test001"}){id name}
Directive code
isAuthenticated: async (next, source, args, ctx) => {
let user = ctx.prisma.context.user(where: {})// Need to fetch the user with given id
}
How can I fetch the user with given id in directives code. I did not get id in args variable. Is there a way to get UserWhereUniqueInput value in directive?

Related

Know specified fields on serverside in GraphQL / Sangria-Graphql

When a client sends a request, I want to know what are the fields client has requested for data. For example,
{
user {
name
address
}
}
In the above request, client has requested name field and address field of the user. how do I know/get these specified fields i.e. name and address in the sangria-graphql Server while executing the query?
you have to use 4th parameter in resolve()
resolve: (obj, args, auth, fieldASTs) => {
/* all your fields are present in selections
please check the fieldASTs JSON path it may vary if you are using relay
connections */
const requiredFields = fieldASTs.fieldNodes[0].selectionSet.selections.map(
(set) => set.name.value
);
// requiredFields will contain the name and address
}
/* fieldASTs contains fieldNames, fieldNodes and every details about your Schema
you can get your specified fields inside fieldNodes like */

REST Api with QueryParamAuth authenticator - Yii2

I'm trying to create rest api for my application to get the data in my android app. This is my controller
<?php
namespace api\modules\v1\controllers;
use yii\rest\ActiveController;
use yii\filters\auth\QueryParamAuth;
/**
* Tk103 Controller API
*/
class Tk103Controller extends ActiveController
{
public $modelClass = 'api\modules\v1\models\Tk103CurrentLocation';
public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['authenticator'] = [
'class' => QueryParamAuth::className(),
];
return $behaviors;
}
}
I added access_token column in my user table, implemented findIdentityByAccessToken() in User Model and calling this URL
http://localhost:7872/api/v1/tk103s?access-token=abcd
This is working great and returning data if and only if access_token matches with any single user in the table.
I checked QueryParamAuth class and found that QueryParamAuth::authenticate() returns $identity after successful authentication.
Currently this url is returning whole data of my table.
What I want is(after authentication):
Get user id/username of the requester.
Based on that id/username, the data related to him as per relations of tables in db. (currently whole rows are being returned but I want only few that are matching with the current requester/user)
I tried but didn't getting any clue to catch returned $identity of user after authentication.
And I know it is possible too to make this work. Help me out folks to create magic.
Get user id/username of the requester.
That user instance you did return within the findIdentityByAccessToken method should be accessible any where inside your app within Yii::$app->user->identity. And should hold all the attributes retreived from DB. here is a quick example of using it to check access within the checkAccess method of the ActiveController class:
public function checkAccess($action, $model = null, $params = [])
{
// only an image owner can request the related 'delete' or 'update' actions
if ($action === 'update' or $action === 'delete') {
if ($model->user_id !== \Yii::$app->user->identity->id)
throw new \yii\web\ForbiddenHttpException('You can only '.$action.' images that you\'ve added.');
}
}
Note that the checkAccess is by default an empty method that is manually called inside all the built-in actions in ActiveController. the Idea is to pass the action ID and the model instance to it just after retrieving it from DB and before modifying it so we can do extra checks. If you just need to perform checks by actions ID then yii\filters\AccessControl may be enough but inside checkAccess you are expecting to also get the model instance itself so it is important to note that when building your own actions or overriding existing onces. be sure to manually invoke it the same way it is done in UpdateAction.php or DeleteAction.php.
whole rows are being returned but I want only few .. matching with .. current requester/user
It depends on how your data is structured. You can override ActiveController's actions to filter results before outputting them, it can be handled in the related SearchModel class if you are using one or it can be handled in model. A quick tip may be by simply overriding the find method inside your model:
public static function find()
{
return parent::find()->where(['user_id' => Yii::$app->user->getId()]); // or Yii::$app->user->identity->id
}
Note that this works only when using ActiveRecord. Which means when using this:
$images = Image::find()->all();
The find method we just overriden will be filtered by default by always including that where condition before generating the DB query. Also note the default built-in actions in ActiveController are using ActiveRecords but if you are using actions where you are constructing the SQL queries using the Query Builder then you should manually do the filtering.
The same can be done if using ActiveQuery (maybe better explained here) by doing this:
public static function find()
{
$query = new \app\models\Image(get_called_class());
return $query->andWhere(['user_id' => Yii::$app->user->getId()]);
}

Modify routing in Sails to use something else than id?

I have a web app which talks to my backend node.js+sails app through a socket.
Default routes for sockets use id. As example
io.socket.get('/chatroom/5')
My app doesn't authenticate users and as result I want id's to be random, so nobody can guess it. However, id's are generated by mongoDB and aren't that random.
As result, I want to use some other field (a.e. "randomId") and update routing for this model to use this field instead of id.
What's the best way to do it?
P.S. It looks like I have to use policies, but still struggling to figure out what should I do exactly.
You aren't forced to use the default blueprint routes in your app; you can always override them with custom controller methods or turn them off entirely.
The GET /chatroom/:id method automatically routes to the find action of your ChatroomController.js file. If you don't have a custom action, the blueprint action is used. So in your case, you could define something like the following in ChatroomController.js:
find: function (req, res) {
// Get the id parameter from the route
var id = req.param('id');
// Use it to look up a different field
Chatroom.find({randomId: id}).exec(function(err, chatrooms) {
if (err) {return res.serverError(err);}
// Subscribe to these rooms (optional)
Chatroom.subscribe(req, chatrooms);
// Return the room records
return res.json(chatrooms);
});
}
If you don't like the name find or the param id, you can set your own route in config/routes.js:
"GET /chatroom/:randomid": "ChatroomController.myFindActionName"
Also, re:
Default routes for sockets use id.
those routes aren't just for sockets--they respond to regular HTTP requests as well!
I created a policy. This policy converts randomId (which is passed as :id) to real id and saves it in req.options.id (which Sails will pick up).
module.exports = function(req, res, next) {
var Model = req._sails.models[req.options.model];
var randomId = req.params.all()['id'];
Model.findOne().where({ randomId: randomId }).exec(function(err, record) {
req.options.id = record.id;
return next();
});
};
And I apply this policy to findOne and update actions of my controller:
ChatRoomController: {
findOne : 'useRandomId',
update : 'useRandomId'
}

Angular.js Dynamic Binding when posting to restful server

I am somewhat confused of the way to achieve the two-way data binding when posting to my server.
I defined my resource like this:
angular.module('todoServices', ['ngResource']).
factory('Todo', function($resource){
return $resource('api/v1-0/todos/:todoId', {}, {
query: {method: 'GET', params:{todoId:''}, isArray: true},
save: {method: 'POST', isArray: true}
});
})
and I pass the Todo resource to my controller as a dependency.
Then in my controller I have a method to add a new Todo item to my list:
$scope.addTodo = function() {
var savedModel = new Todo();
savedModel.title = $scope.title;
savedModel.description = $scope.description,
//...
savedModel.$save();
$scope.todos.push(savedModel);
}
This works as far as my todo appears in the list, the call to the server works and the item is added in my database.
However, since when I push it to my list, it does not have an ID, yet. The ID is generated by an auto-increment ID in my MySQL database.
My server returns the object in JSON format, so I assume, I have to specify some sort of callback function to get the data-binding to work?
What exactly do I need to do, so my todo which has been added is updated with the correct ID once my server returns the data?
Simply assign the returned object to the savedModel object. Since calls to resources are asynchronous and return a promise, you should use the success function this way:
savedModel.$save(
function success(savedModel) {
$scope.todos.push(savedModel);
});
By the way, check the isArray property of the save method, normally should be false.

Grails spring-security-facebook plugin's accessToken

I'm using the spring-security-facebook plugin for authentication. It works well, now I'm trying to use some functions of spring-social-facebook that needs authorization. From my controller, where can I get a valid accessToken (in order to create a FacebookTemplate object) ?
This is how I'm using the plugin:
1) I added a domain class, OAuthUser (not in the plugin but in my project)
2) I have generated a FacebookAuthDaoImpl
3) I edited the methods generated, for example in create(), I create
+ an instance of a user (main domain class SecUser) and set the profile infos
+ a new OAuthUser (where I set the uid, the accessToken, and relate it to the main user created.
UPDATE 1:
I added those 3 methods in my FacebookAuthDaoImpl class:
Boolean hasValidToken(OAuthUser user){
def now= new Date()
if(now.after(user.accessTokenExpires)){
return false
} else {
return true
}
}
void updateToken(OAuthUser user, FacebookAuthToken token){
user.accessToken = token.accessToken
user.save()
}
String getAccessToken(OAuthUser user){
return user.accessToken
}
But I still have the expired AccessToken.
If you're using default DAO:
It's stored at field accessToken of your domain object for Facebok User.
If you don't have field named accessToken, you should add it (String accessToken). Ideally with an additional field: Date accessTokenExpires. And both fields will be automatically filled by the plugin.
If you've created your own DAO implementation, then:
create(FacebookAuthToken token) pass access token as token.accessToken.accessToken. You can store it anywhere you wish
Boolean hasValidToken(F user), void updateToken(F user, FacebookAuthToken token) and getAccessToken(F user) - first should check token expiration, second update with new value (called when token is expired) and last should retourn current value.
As you said, you have you own DAO implentation. How you're implemented last 3 methods?