equivalent to global "before_filter" in Yesod - authentication

I have been attempting to play with Yesod, and I have run into a very simple problem that I can not seem to find a solution to.
Say I want to have a global function, that runs on every request irrelevantly of route or handler (for example an authentication function). Say I want something like
uid <- requireAuthId
to run before every handler function and return control to the handler function when a uid is provided / if it already exists
Where would I slot this in? What is the 'Yesod Way' of doing before filters?

One way to do this is to modify your Yesod instance for your foundation type. Assuming your foundation type is called App, you can do the following to force authorization before any other handlers are called.
instance Yesod App where --the following lines are somewhere within this block.
isAuthorized (AuthR LoginR) _ = return Authorized -- You don't want to accidentally lose access to the login page!
isAuthorized _ _ = do
mauth <- maybeAuth
case mauth of
Just _ -> return Authorized
Nothing -> return $ Unauthorized "You must login first."
Obviously, edit this to suit your needs, but it should give you an idea of how to do this.

Related

How to create "Round Robin Call Forwarding Function" in Twilio Stack

I have researched high and low through multiple websites and have not found a single fully documented solution for round-robin call forwarding with-in the Twilio stack; let alone within Twilio Studio. The last time this question was asked in detail was in 2013 so your help is greatly appreciated. I am looking to find a solution to the following to educate myself and others:
[Round Robin Scenario]
Mentioned by Phil Krnjeu on Aug 1 '13 at 23:04, "I'm trying to create a website that has a phone number on it (say, a phone number for a school). When you call that number, it has different secretary offices (A,B,C, D). I want to create something where the main number is called, and then it goes and calls phone number A the first time, the second time someone calls the main number, number B is called, C, then D. Once D is called (which would be the 4th call), the 5th call goes back to A."
The response to the above question was to use an IVR Screening & Recording application which requires the caller to pick an agent which is not a true Round Robin solution. The solution I am looking for and many others require the system to know which agent is in a group and which agent is next to receive a call.
[Key Features Needed]
Ability to add forwarding numbers as identified above A, B, C, D as a group or IVR extensions such as 1 = Management, 2 = Sales and etc...
Set a subsequent calling rule that notates in a DB of some sort. Caller A through D, for example, equals 1 unsuccessful. When caller A has been forwarded a call it now equals 0 successful then the script stops and allows the call to be answered by the user or its voicemail. Then the next call comes in and is forwarded to user B and assigned a 0 successful value, then the script stops.
After the caller finishes the call or finishes leaving a voicemail the script needs to end the call.
[Final Destination]
The round-robin should finalize its call with the forwarded phone numbers voicemail.
[Known Issues]
Forwarding a call to multiple numbers not stopping when someone answers
[Options]
Once this question is posted I am sure someone will ask in the near future what if I wanted the call to be forwarded to a Twilio voicemail instead of using the forwarded phone number's voicemail which could be let's say a cell phone. I do not necessarily need this feature, however, making an additional comment would be very helpful to the community. Thank you for your time.
I have limited knowledge of programming besides having the ability to review articles posted by other users. One article I researched in detail that did not work for me was, "IVR: Screening & Recording with PHP and Laravel."
The solution I am looking for first would be to make this code through the new Twilio Studio interface if that is not possible then any other solution would be helpful to all.
Sam here from the Twilio Support Team. You can build what you've described using Twilio's Runtime suite, Studio, and Functions.
I wrote a blog post with detailed instructions and screenshots here, and I've included a summarized version below as well.
CREATE YOUR VARIABLE
First, you need to create a serverless Variable which will be used as the round robin counter. The variable must be inside an Environment, which is inside a Service. This is the only part of the application where you will need your own laptop. You can see how to create these with any of the SDKs or using curl in the docs.
Create a Service
Create an Environment
Create a Variable
Be sure to copy the SIDs of your Service, Environment, and Variable since you will need that for your function.
For convenience, this is how you create the Variable in NodeJS.
const accountSid = 'your_account_sid';
const authToken = 'your_auth_token';
const client = require('twilio')(accountSid, authToken);
client.serverless.services('ZSXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
.environments('ZEXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
.variables
.create({key: 'key', value: 'value'})
.then(variable => console.log(variable.sid));
CREATE YOUR FUNCTION
Create the following Environment Variables here in the console and save set them equal to their respective SID that you saved earlier.
RR_SERVICE_SID
RR_ENV_SID
RR_VAR_SID_CTR
Next, make sure you check the Enable ACCOUNT_SID and AUTH_TOKEN checkbox above the Environment Variables section under Credentials.
Be sure your Twilio Client version in the Dependencies section is set to the latest, so we can be sure it includes the Serverless resources. At the time of writing (March 2020), the default Client version does not include them, so we upgraded to 3.41.1, which was the latest.
Go here in the console and create a blank Function.
Copy and paste the following code and replace the numbers with the ones you would like to include in your Round Robin (make sure the environment variables you just created match what's in the code).
exports.handler = function(context, event, callback) {
// Number List
let numbers = [
"+18652142345", //Sam
"+18651092837", //Tina
"+19193271892", //Matt
// Copy and paste line above to add another number.
];
// Initialize Twilio Client
let client = context.getTwilioClient();
// Fetch Round Robin Ctr
client.serverless.services(context.RR_SERVICE_SID)
.environments(context.RR_ENV_SID)
.variables(context.RR_VAR_SID_CTR)
.fetch()
.then(variable => {
// Use counter value to determine number to call
let number = numbers[variable.value];
// Create var with new ctr value
let ctr = variable.value;
// Check if current counter value is less than RR length (i.e. the number of numbers in round robin)
// If so, increment
if(ctr == numbers.length-1) {
ctr = 0;
}
// Otherwise reset ctr
else ctr++;
// Update counter value
client.serverless.services(context.RR_SERVICE_SID)
.environments(context.RR_ENV_SID)
.variables(context.RR_VAR_SID_CTR)
.update({value: ctr})
.then(resp => {
// Return number to call
let response = {number};
// Return our counter value and a null error value
callback(null, response);
});
});
};
CREATE YOUR STUDIO FLOW
Click the red plus sign to create a new Flow here.
Give the Flow a name and click Next.
Scroll to the bottom of the templates and click 'Import from JSON' and click Next.
Paste the Flow JSON shown here and click Next.
Click the RoundRobin function widget and select the Function you just created under the Default service.
Click the FunctionError widget, click MESSAGING & CHAT CONFIG, and change the SEND MESSAGE TO number to a number that you would like to notify by text in the event of a Function failure.
Click the DefaultNumber widget and change the default number that will be forwarded to in the event of a Function failure.
Click the Publish button at the top of your Flow.
CONFIGURE YOUR TWILIO NUMBER
Go here in the console.
Click the Twilio number you would like to configure.
Scroll down to the A CALL COMES IN dropdown in the Voice section and select Studio Flow.
Select your new Flow in the Select a Flow dropdown to the right.
Click Save at the bottom.
And that's it. You're now all set to test!

Bloomberg API - How to get user entitlements for user subscription

i'm just trying to check user entitlements for user subscription data from bloomberg api's data feeds.
For this i tried to run Bloombergs example "EntitlementsVerificationSubscriptionExample". As it seems to be working at first sight, on second sight i recognized, that there aren't any entitlements for the data i receive from the api.
that means:
public void processSubscriptionDataEvent(Event eventObj, Session session)
{
foreach(Message msg in eventObj)
{
bool needsEntitlement = msg.HasElement(Name.GetName("EID"));
}
}
is always 'false', as there is never a field called "EID" available.
Is there something wrong on bloomberg service site or better, is there any kind of documentation available, how to use user entitlements within data subscriptions?
thanks in advance,
First, you need to subscribe to the "EID" field, as it's not returned by default.
If the field either is not returned in the message, or had Null value, then that means data in this message does not require entitlements. Otherwise, call the following function and pass the EID value:
bool bEntitled = userIdentity.hasEntitlements(EID);
Function return value indicates whether user is entitled or not.
Data that does not require entitlements can be shared with users who are registered in EMRS (in case of B-Pipe), or with any terminal user within the firm (in case of SAPI) with no further entitlement check. Users who are not registered in EMRS or those who are non-terminal users should not have access to either B-Pipe data, or SAPI data, respectively.

Changing Postman request name from prerequest script

I'm currently trying to implement few Postman requests with CSV data sources.
For instance let assume I have request named "Open as user".
In csv file, I have bunch of user credentials with description field that describes user role.
I would like to have the ability to change request names to reflect each user roles.
For instance, if the request is made as the admin user I would like request name in reports and runner to be "Open as user admin".
In documentation, I've found pm.info.requestName variable but seems it is read-only.
I put following in Pre-request Script
pm.info.requestName = "1";
console.log(pm.info.requestName);
but got "Open as user" value instead of assigned "1".
Have anyone tried to do the same trick or know whether it is possible at all?
I was looking for a solution to this as well and i have solved it in the following way:
Use the 'Pre-request Script' to determine what role the user has.
Set the url to a environment- or global-variable
Use that url in the request, like {{url}}
Clear the environment- or global-variable in the 'Tests' tab
In my case i used the environment variable to get the environment, instead of you, using the data variables.
var environment = pm.environment.get("environment");
var url;
switch(environment) {
case "test":
url = pm.globals.get("test-url");
break;
case "acc":
url = pm.globals.get("acc-url");
break;
case "prod":
url = pm.globals.get("prod-url");
break;
default:
url = pm.globals.get("test-url");
break;
}
pm.environment.set("url", url);
Hope this helps!
I'm afraid that you can't do that. pm.request object is available only after request execution. I even think that you can't access the request name the way you want (I though I would find it in the 'id' member, but it was empty)
Have a look here to see what's available in terms of members and methods concerning the request object.
You may find another way of proceeding (maybe duplicate your test, rename it with admin and, under proper condition, launch the admin request instead of the common user request ? it's kind of a hassle just for a test name)
I think about something else: you could just customize your assertions label, that's what I do to have 'readable' test names in TFS reports. In the Tests tab :
test_name = "[ "+ request.name + " ] - ";
and for each assertion (example):
tests[test_name + "Status code is 200"] = responseCode.code === 200;
This gives, in the response Tests tab, something like :
PASS [Get all configuration]-Status code is 200
Under a particular condition, you can replace request.name with a custom string or do request.name + "admin" ...
hope this helps

How do you use Snap's authentication mechanisms during a single POST request?

I'm working on a Haskell Snap-based web app, and I want to expose an API endpoint that will be invoked by a remote service without establishing an authenticated session a-priori; however, I do want that request to be authenticated, so the credentials should be provided at the time of the request.
You could imagine the request containing four fields:
username
password
payload id
payload file
The payload id and file might be irrelevant for this question, but I include them because I (a) need to support file uploads in this request (which, as I understand it, restricts the encoding used to send fields) and (b) need to retrieve at least one non-file field. The combination of those things posed some difficulty when I set this up without authentication, so perhaps it is relevant.
In Snap parlance, let's call this handler uploadHandler.
As indicated above, I have this working fine without authentication, with a setup like this:
uploadHandler :: Handler App App ()
uploadHandler = do
-- collect files / form fields and process as needed.
-- and using the routes:
routes :: [(ByteString, Handler App App ())]
routes = [ ("/login", with auth handleLoginSubmit)
, ("/logout", with auth handleLogout)
, ("/new_user", with auth handleNewUser)
-- handle the upload:
, ("/upload", handleUpload)
]
The naive solution is to simply add 'with auth' and change the type of handleUpload:
uploadHandler :: Handler App (AuthManager App) ()
uploadHandler = do
-- collect files / form fields and process as needed.
-- and using the routes:
routes :: [(ByteString, Handler App App ())]
routes = [ ("/login", with auth handleLoginSubmit)
, ("/logout", with auth handleLogout)
, ("/new_user", with auth handleNewUser)
-- handle the upload, with auth:
, ("/upload", with auth handleUpload)
]
However, this seems to require two requests: (i) authenticate and establish a session, (ii) send the POST request containing the actual payload.
I found a way to do this in one request, but it seems like there should be a more elegant means. Here's the example restricted POST handler I've hacked together:
restrictedPOST :: Handler App (AuthManager App) ()
restrictedPOST = do
mName <- getPostParam "username"
mPass <- getPostParam "password"
let uName = C8.unpack $ fromMaybe "" mName
pass = ClearText $ fromMaybe "" mPass
authResult <- loginByUsername (T.pack uName) pass False
case authResult of
Left authFail -> writeText "Could not log in"
Right user -> writeText (T.append "Hello " (userLogin user))
Is there something like 'with auth' that I can use instead of turning this example (restrictedPOST) into a combinator? I realize it may need to know which fields to get credentials out of, but I also know very little about web services (maybe there is another means? Maybe this is a total non-issue, and I just don't know how to check auth for POST requests. I'm open to any suggestions!)
I don't think you understand what with auth is doing. It has nothing to do with whether authentication is required. All it does is convert a Handler b (AuthManager b) into a Handler b v. No permissions checks are performed. Your restrictedPOST function has the right idea.

Login as user without password (For an Admin Use-Case.)

To check if the view of a user is working or to make change out of the users view point (in development) it can be quite useful to incarnate a certain user.
How would I do this with Meteor? Best would be a solution which is independent of the Account Authentication.
To impersonate a user in production, you can call setUserId on the server, and Meteor.connection.setUserId on the client. For more details, see my blog post.
If you're using Meteor.userId() and Meteor.user() to identify your person in your javascript you could use something like this to override it at the very top of your client js
Meteor.userId = function (impersonate_id) {
return (impersonate_id) ? impersonate_id : Meteor.default_connection.userId();
}
Meteor.user = function (impersonate_id) {
var userId = Meteor.userId(impersonate_id);
if (!userId)
return null;
return Meteor.users.findOne(userId);
}
And now when you use Meteor.userId or Meteor.user modify your code so everywhere you use Meteor.user & Meteor.userId accepts an argument. So when you want to impersonate a user just pass it argument of the _id of the user you want to log in as
Meteor.user("1"); //Loads the data for user with _id 1
Meteor.user(); //Loads the actual logged in user
Also this will only work if you're actually the admin and your publish function allows you to see all your user's data