I currently setup the role based and content authorization. However i got problem when I try the to access the route of super admin still accessible. I used this instruction https://medium.com/justlaravel/how-to-use-middleware-for-content-restriction-based-on-user-role-in-laravel-2d0d8f8e94c6 - but still no working well.
to understand well, I will share to you what suppose to be the output and my sample coding on my middleware and api.php
I have Middleware of CheckRoleRouter.php
I create a unauthorized.blade.php file for new response if the user role access wrong route.
I already set the middleware to the kernel.php
Role: I have Super Admin = 0 and Admin = 1
Middleware:
<?php
namespace App\Http\Middleware;
use Closure;
use Auth;
class CheckRoleRouter
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
//Role of users
//Super Admin = 0
//Admin = 1
// how to make a middleware to prevent accessing other router based on their role.
if ($request->user() && $request->user()->role != 0)
{
return new Response(view('unauthorized')->with('role', 'SUPERADMIN'));
}
return $next($request);
}
}
Api:
Route::group(['middleware' => 'App\Http\Middleware\CheckRoleRouter'], function()
{
Route::get('list_offers','Api\BusinessOffersController#list_offers');
});
Kernel:
'checker' => \App\Http\Middleware\CheckRoleRouter::class,
Session: - it means i used the admin role so the logic is the router of super_admin is not accessible anymore because i used the admin.
Page:
I'm trying to run two tasks in parallel using yield all() but getting the following log error Object(...) is not a function
When I invoke const response = yield call(request, url) on its own it works. Not sure why yield all() doesn't like the request function I'm passing in.
Here is the code,
const url = `${apiHost}${getSpecificTestConfiguration.endpoint}${configurationId}`;
const [response, itemPool] = yield all([
call(request, url),
put(getItemPool(itemPoolId)),
]);
and here is the request function passed into the call effect where the error is thrown
/**
* Requests a URL, returning a promise
*
* #param {string} url The URL we want to request
* #param {object} [options] The options we want to pass to "fetch"
* #return {object} An object containing either "data" or "err"
*/
export default function request(url, options = {}) {
const opts = addHeaders(options);
return fetch(url, opts)
.then(checkStatus)
.then(parseJSON)
.then((data) => ({ data }));
}
Any help would be greatly appreciated.
Thanks,
My earlier comment was definitely off-base.
Make sure your version of redux-saga is 0.15.0 or higher. This is when all was added.
I was able to reproduce your exact issue in my project using version 0.14.X and the following import: import { ..., all } from 'redux-saga/es/effects, which very helpfully does NOT complain that all doesn't exist. Issue was solved by updating to ^0.15.0 and importing from 'redux-saga/effects'.
Hope this helps.
I'm trying to inject a third party script onto a page and once its loaded initialise a video player.
I want to be able to have multiple video players on any page so I have some logic to check whether the script is already loaded and fire a different actions depending on whether it is or not.
My "script loading" helper looks like this:
/**
* injectScript - Inject player script into page
* #param {String} id - script tag id
* #param {String} src - script src
* #return {Promise} - script load callback
*/
injectScript (id, src) {
return new Promise(resolve => {
if (!document.getElementById(id)) {
const script = document.createElement('script');
script.setAttribute('id', id);
script.type = 'text/javascript';
script.src = src;
document.body.appendChild(script);
script.onload = () => resolve('script-loaded');
} else {
resolve('script-exists');
}
});
}
I then have an epic which calls this helper and fires an action depending on the outcome. The epic looks like this:
/**
* loadPlayerScript
* #param {Object} action$ - action observable
* #param {Object} store - redux store
* #param {Object} dependencies - injected dependencies
* #return {Object} - action observable
*/
export default function loadPlayerScript (action$, store, { scriptLoaderHelper }) {
return action$.ofType(PLAYER_SCRIPT_LOAD)
.switchMap(action => Observable.fromPromise(scriptLoaderHelper.injectScript(action.data.id, action.data.script)))
.map(data => {
if (data === 'script-loaded') {
return playerScriptSuccess();
}
return playerScriptExists();
})
.catch(error => Observable.of(playerScriptFailure(error)));
}
The problem:
The PLAYER_SCRIPT_LOAD gets fired twice (I can validate this in Redux dev tools), this is expected. Whats happening though is the epic is only resolving the promise once (and it only fires one of the actions in the map). How do I get the epic to fire the actions for each promise resolve?
I'm sure its something super simple that I'm overlooking but any helps is appreciated!
Change switchMap to mergeMap to avoid cancellation:
The main difference between switchMap and other flattening operators is the cancelling effect. On each emission the previous inner observable (the result of the function you supplied) is cancelled and the new observable is subscribed. You can remember this by the phrase switch to a new observable.
source: https://www.learnrxjs.io/operators/transformation/switchmap.html
I’m having issues figuring out how to connect the Relay Modern network layer with my websocket instance.
I’m currently instantiating a websocket instance as:
const subscriptionWebSocket = new ReconnectingWebSocket('ws://url.url/ws/subscriptions/', null, options);
I'm specifying the subscription and creating a new instance of requestSubscription:
const subscription = graphql`
subscription mainSubscription {
testData {
anotherNode {
data
}
}
}
`;
requestSubscription(
environment,
{
subscription,
variables: {},
onComplete: () => {...},
onError: (error) => {...},
onNext: (response) => {...},
updater: (updaterStoreConfig) => {...},
},
);
Which then allows me to send any subscription requests:
function subscriptionHandler(subscriptionConfig, variables, cacheConfig, observer) {
subscriptionWebSocket.send(JSON.stringify(subscriptionConfig.text));
return {
dispose: () => {
console.log('subscriptionHandler: Disposing subscription');
},
};
}
const network = Network.create(fetchQuery, subscriptionHandler);
through to my server (currently using Graphene-python), and I’m able to interpret the received message on the server.
However, what I’m having issues figuring out is how to respond to a subscription; for example, when something changes in my DB, I want to generate a response and return to any potential subscribers.
The question being, how do I connect the onMessage event from my websocket instance into my Relay Modern Network Layer? I've browsed through the source for relay but can't seem to figure out what callback, or what method should be implementing an onreceive.
Any tips are appreciated.
I've managed to make subscriptions with Relay Modern work as well and wanted to share my minimal setup, maybe it's helpful for someone!
Note that I'm not using WebSocket but the SubscriptionClient that can be found in subscriptions-transport-ws to manage the connection to the server.
Here's my minimal setup code:
Environment.js
import { SubscriptionClient } from 'subscriptions-transport-ws'
const {
Environment,
Network,
RecordSource,
Store,
} = require('relay-runtime')
const store = new Store(new RecordSource())
const fetchQuery = (operation, variables) => {
return fetch('https://api.graph.cool/relay/v1/__GRAPHCOOL_PROJECT_ID__', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
query: operation.text,
variables,
}),
}).then(response => {
return response.json()
})
}
const websocketURL = 'wss://subscriptions.graph.cool/v1/__GRAPHCOOL_PROJECT_ID__'
function setupSubscription(
config,
variables,
cacheConfig,
observer,
) {
const query = config.text
const subscriptionClient = new SubscriptionClient(websocketURL, {reconnect: true})
const id = subscriptionClient.subscribe({query, variables}, (error, result) => {
observer.onNext({data: result})
})
}
const network = Network.create(fetchQuery, setupSubscription)
const environment = new Environment({
network,
store,
})
export default environment
NewLinkSubscription.js
import {
graphql,
requestSubscription
} from 'react-relay'
import environment from '../Environment'
const newLinkSubscription = graphql`
subscription NewLinkSubscription {
Link {
mutation
node {
id
description
url
createdAt
postedBy {
id
name
}
}
}
}
`
export default (onNext, onError, onCompleted, updater) => {
const subscriptionConfig = {
subscription: newLinkSubscription,
variables: {},
onError,
onNext,
onCompleted,
updater
}
requestSubscription(
environment,
subscriptionConfig
)
}
Now you can simply use the exported function to subscribe. For example, in one of my React components in componentDidMount I can now do the following:
componentDidMount() {
NewLinkSubscription(
response => console.log(`Received data: `, response),
error => console.log(`An error occurred:`, error),
() => console.log(`Completed`)
)
}
Note that the SubscriptionClient can only be used if your server implements this protocol!
If you want to learn more, check out the fullstack How to GraphQL tutorial that describes in detail how to make subscriptions work with Relay Modern.
I’ll just write down how I’ve approached this issue after the assistance found in this thread. It might be usable for someone else. This is very dependent on the server-side solution that you've chosen.
My approach:
Firstly I built a SubscriptionHandler that will handle the requestStream#subscribeFunction through SubscriptionHandler#setupSubscription.
The SubscriptionHandler instantiates a WebSocket (using a custom version of ReconnectingWebSockets) and attaches the onmessage event to an internal method (SubscriptionHandler#receiveSubscriptionPayload) which will add the payload to the corresponding request.
We create new subscriptions through SubscriptionHandler#newSubscription which will use the internal attribute SubscriptionHandler.subscriptions to add a keyed entry of this subscription (we use an MD5-hash util over the query and variables); meaning the object will come out as:
SubscriptionHandler.subscriptions = {
[md5hash]: {
query: QueryObject,
variables: SubscriptionVariables,
observer: Observer (contains OnNext method)
}
Whenever the server sends a subscription response the SubscriptionHandler#receiveSubscriptionPayload method will be called and it will identify what subscription the payload belongs to by using the query/variables md5 hash, then use the SubscriptionHandler.subscriptions observer onNext method.
This approach requires the server to return a message such as:
export type ServerResponseMessageParsed = {
payload: QueryPayload,
request: {
query: string,
variables: Object,
}
}
I do not know if this is a great way of handling subscriptions, but it works for now with my current setup.
SubscriptionHandler.js
class SubscriptionHandler {
subscriptions: Object;
subscriptionEnvironment: RelayModernEnvironment;
websocket: Object;
/**
* The SubscriptionHandler constructor. Will setup a new websocket and bind
* it to internal method to handle receving messages from the ws server.
*
* #param {string} websocketUrl - The WebSocket URL to listen to.
* #param {Object} webSocketSettings - The options object.
* See ReconnectingWebSocket.
*/
constructor(websocketUrl: string, webSocketSettings: WebSocketSettings) {
// All subscription hashes and objects will be stored in the
// this.subscriptions attribute on the subscription handler.
this.subscriptions = {};
// Store the given environment internally to be reused when registering new
// subscriptions. This is required as per the requestRelaySubscription spec
// (method requestSubscription).
this.subscriptionEnvironment = null;
// Create a new WebSocket instance to be able to receive messages on the
// given URL. Always opt for default protocol for the RWS, second arg.
this.websocket = new ReconnectingWebSocket(
websocketUrl,
null, // Protocol.
webSocketSettings,
);
// Bind an internal method to handle incoming messages from the websocket.
this.websocket.onmessage = this.receiveSubscriptionPayload;
}
/**
* Method to attach the Relay Environment to the subscription handler.
* This is required as the Network needs to be instantiated with the
* SubscriptionHandler's methods, and the Environment needs the Network Layer.
*
* #param {Object} environment - The apps environment.
*/
attachEnvironment = (environment: RelayModernEnvironment) => {
this.subscriptionEnvironment = environment;
}
/**
* Generates a hash from a given query and variable pair. The method
* used is a recreatable MD5 hash, which is used as a 'key' for the given
* subscription. Using the MD5 hash we can identify what subscription is valid
* based on the query/variable given from the server.
*
* #param {string} query - A string representation of the subscription.
* #param {Object} variables - An object containing all variables used
* in the query.
* #return {string} The MD5 hash of the query and variables.
*/
getHash = (query: string, variables: HashVariables) => {
const queryString = query.replace(/\s+/gm, '');
const variablesString = JSON.stringify(variables);
const hash = md5(queryString + variablesString).toString();
return hash;
}
/**
* Method to be bound to the class websocket instance. The method will be
* called each time the WebSocket receives a message on the subscribed URL
* (see this.websocket options).
*
* #param {string} message - The message received from the websocket.
*/
receiveSubscriptionPayload = (message: ServerResponseMessage) => {
const response: ServerResponseMessageParsed = JSON.parse(message.data);
const { query, variables } = response.request;
const hash = this.getHash(query, variables);
// Fetch the subscription instance from the subscription handlers stored
// subscriptions.
const subscription = this.subscriptions[hash];
if (subscription) {
// Execute the onNext method with the received payload after validating
// that the received hash is currently stored. If a diff occurs, meaning
// no hash is stored for the received response, ignore the execution.
subscription.observer.onNext(response.payload);
} else {
console.warn(Received payload for unregistered hash: ${hash});
}
}
/**
* Method to generate new subscriptions that will be bound to the
* SubscriptionHandler's environment and will be stored internally in the
* instantiated handler object.
*
* #param {string} subscriptionQuery - The query to subscribe to. Needs to
* be a validated subscription type.
* #param {Object} variables - The variables for the passed query.
* #param {Object} configs - A subscription configuration. If
* override is required.
*/
newSubscription = (
subscriptionQuery: GraphQLTaggedNode,
variables: Variables,
configs: GraphQLSubscriptionConfig,
) => {
const config = configs || DEFAULT_CONFIG;
requestSubscription(
this.subscriptionEnvironment,
{
subscription: subscriptionQuery,
variables: {},
...config,
},
);
}
setupSubscription = (
config: ConcreteBatch,
variables: Variables,
cacheConfig: ?CacheConfig,
observer: Observer,
) => {
const query = config.text;
// Get the hash from the given subscriptionQuery and variables. Used to
// identify this specific subscription.
const hash = this.getHash(query, variables);
// Store the newly created subscription request internally to be re-used
// upon message receival or local data updates.
this.subscriptions[hash] = { query, variables };
const subscription = this.subscriptions[hash];
subscription.observer = observer;
// Temp fix to avoid WS Connection state.
setTimeout(() => {
this.websocket.send(JSON.stringify({ query, variables }));
}, 100);
}
}
const subscriptionHandler = new SubscriptionHandler(WS_URL, WS_OPTIONS);
export default subscriptionHandler;
For anyone stumbling across this recently, I did not have success with either the solutions above because of recent updates in the libraries involved. Yet they were a great source to start and I put up together a small example based on the official relay modern todo example, it is very minimalistic and uses helpers libraries from Apollo but works well with relay modern:
https://github.com/jeremy-colin/relay-examples-subscription
It includes both server and client
Hope it can help
I think this repo would fit your needs.
Helps you creating your subscriptions server-side
I am using AngularJS for a web development project and I'm stuck because I am trying to store the user session in a cookie so that it's impossible for them to access login or registration page when they are already logged in, and also for various other reasons.
What seems to be happening is that I am storing user data into a cookie, and i used console.log() to return the data stored in the cookie and the storing process seems to be working. However, when I attempt to access the login screen, I am still able to do so.
So for debugging purposes I added another console.log() to check the data stored in the cookie when the login page is accesed and it returns as undefined.
Does anyone know what's the issue in my code that is causing the data to be dumped?
function login(email, password, callback) {
return $http.post('/api/v1/auth/login/', {
email: email,
password: password
}).then(function(data, status, headers, config) {
Authentication.setAuthenticatedAccount(data.data);
window.location = '/:username';
}, function (response) {
var response;
response = { success: false, message: 'Username or password is incorrect' };
callback(response);
console.error('Epic failure!');
});
/**
* #name getAuthenticatedAccount
* #desc Return the currently authenticated account
* #returns {object|undefined} Account if authenticated, else `undefined`
* #memberOf hrlite.authentication.services.Authentication
*/
function getAuthenticatedAccount() {
if (!$cookies.authenticatedAccount){
return;
}
return $cookies.getObject('authenticatedAccount');
}
/**
* #name isAuthenticated
* #desc Check if the current user is authenticated
* #returns {boolean} True is user is authenticated, else false.
* #memberOf hrlite.authentication.services.Authentication
*/
function isAuthenticated() {
console.log("account:" + getAuthenticatedAccount());
return !!$cookies.authenticatedAccount;
}
/**
* #name setAuthenticatedAccount
* #desc Stringify the account object and store it in a cookie
* #param {Object} user The account object to be stored
* #returns {undefined}
* #memberOf hrlite.authentication.services.Authentication
*/
function setAuthenticatedAccount(account) {
$cookies.putObject('authenticatedAccount', account);
}