Rails and Websockets: need some direction on a feature - ruby-on-rails

In my rails app a User has a profile and this profile can be publicly accessible. I have been looking at using the Pusher gem (https://github.com/pusher/pusher-gem) to use for plug-and-play websocket usage with my app.
Basically I am wanting it so that if a user is looking at a public profile and the owner of that profile happens to update that profile then the front-end is updated with the new information and the user is notified on the front-end about the update.
Any help on where to get started would be great!

For each public profile have a unique channel name e.g. <user_name>-profile.
Whenever an updated occurs on the user user_name's profile trigger an event on the user's channel, passing the updated data.
data = update_profile()
Pusher.trigger( '<user_name>-profile', 'profile-updated', {:profile => data} )
On the profile page running the the browser have the code that listens to updates only on the relevant channel:
var pusher = new Pusher( APP_KEY );
var channel = pusher.subscribe( '<user_name>-profile' );
channel.bind( 'profile-updated', function( update ) {
// Update UI to show new profile information
// Show something to indicate that an update has occurred
} );
The one problem here is that you will be triggering an event even when nobody is viewing the public profile. If you wanted to fix that you would need to use WebHooks and keep track of whether or not a profile channel was occupied and only trigger the event if it is.

Related

Zendesk - How to detect if I Change (before submit) Requester Name in opened Tickets?

I have a server side app, which display customer info such as name, id, email etc based on currently opened ticket.
My next task is to update the Requester name in Zendesk App ( server side app ) if i made changes in Ticket Requester before submit.
is that possible?
You can add custom events using client.on('event_type', handler). Refer to ZAF Client API for available events depending on the location.
Here is an example:
if (client) {
client.on('ticket.requester.name.changed', function(e) {
document.getElementById('requesterNameElementId').innerText = e;
});
} else {
console.log('ZAF Client only works within Zendesk iFrame');
}

Youtube API - Allows Subscribe User but takes away next day

we have a product that will subscribe a user to another user(s) after they go through and give us full permission to do so. The user is then subscribed to these other user(s) ... you can see this in youtube after the API is performed (seems successful) ... but a day later the subscribers are removed and gone? This always worked well. Anyone experience similar issues or know the why here?
When using the API with full permission scope, we Subscribe the user to a channel and we get varying results :
the Google_Service_YouTube_Subscription_Object is returned with valid data
The channel Subscription https://www.youtube.com/subscribers?ar=2&o=U may or may not increase in value (counter at top)
The channel Subscriber list https://www.youtube.com/subscribers?ar=2&o=U is not showing the new user (subscriber)
The user shows in their Youtube view that they are subscribed to the Channel
the user Comment on the video is displayed depending on the user privacy settings
the user Like on the video is counted
the NEXT day: comments, subscriber counts are removed from the Channel, likes on the video seems to stay
$youtube_client = new \Google_Client();
$youtube_client->setClientId(xxxx);
$youtube_client->setClientSecret(xxxx);
$youtube_client->setScopes(xxxx);
$youtube_client->setRedirectUri(xxxx);
$youtube = new \Google_Service_YouTube($youtube_client);
$resourceIdyt = new \Google_Service_YouTube_ResourceId();
$resourceIdyt->setChannelId($channel);
$resourceIdyt->setKind('youtube#channel');
$subscriptionSnippetyt = new \Google_Service_YouTube_SubscriptionSnippet();
$subscriptionSnippetyt->setResourceId($resourceIdyt);
$subscriptionyt = new \Google_Service_YouTube_Subscription();
$subscriptionyt->setSnippet($subscriptionSnippetyt);
$subscriptionResponse = $youtube->subscriptions->insert('id,snippet', $subscriptionyt, array());

How to authenticate user with token (stay authenticated in iPhone)

I have two related questions and I hope someone help me because I've been stuck for 2 days
First: mobile phone failed to authenticate
Here is what I have done:
1- user signs up
2- token released
3- token saved in user's device
but then when the same user try to do API requests I get
Rooute to sign up :
$api = app('Dingo\Api\Routing\Router');
$api->version('v1', function ($api) {
$api->post('auth/signup', 'App\Api\V1\Controllers\AuthController#signup');
then I get a token , so I guess everything looks great!
then now when the same device sends a post request to laravel I get this message
"message": "Failed to authenticate because of bad credentials or an invalid authorization header."
this is the route to the post request
$api->group(['middleware'=>'api.auth'],
function ($api) {
$api->post('auth/ios', 'App\Api\V1\Controllers\AuthController#create');
Second: is my method right to save data made by a mobile phone?
Since I couldn't test this method I'd like to know if this is at least one of the right ways to receive data and save it. The reason to save it is because I will show it in a control panel.
public function create(Request $request)
{
$user = new User();
$id = Auth::id();
$user->phone = $request->input('phone');
$user->city = $request->input('city');
$user->street = $request->input('street');
$user->save();
return 'Employee record successfully created with id ' . $user->id;
}
I understand that you are authenticate users based on api token.
Here is what you could do :
set up a column called api_token in users table by adding the following migration
$table->string('api_token', 60)->unique();.This generates a random api token for every user.
send the api_token back to the user's device and save it there
Send it back with every request. Preferalbly set it up globally and send it in the request Authentication request header
Get the authenticated user like so$user= Auth::guard('api')->user();
Laravel takes care of all the authentication stuff behind the scenes.
Learn More about this here

Identifying users in Rails Web push notifications

I'm developing a Rails application, and I'd like to send web push notifications to specific users when certain actions happen, e.g:
A user started tracking a timer, but the timer has been running for more than 6 hours. Then the app sends that user a web notification.
I've been doing research and found this tutorial, the author implements push notifications for Rails, however there's no insight on how to identify the users.
From what I understood, the users needs to subscribe from their browser to be able to get push notifications, however, considering each user can use the application from multiple browsers, how can I automatically subscribe/unsubscribe a user for notifications in all browsers they use the app from?
So, what I did was adding a notification_subscription model to my User model.
On my javascript, I check if there's a current browser subscription present:
this.serviceWorkerReady()
.then((serviceWorkerRegistration) => {
serviceWorkerRegistration.pushManager.getSubscription()
.then((pushSubscription) => {
if (pushSubscription && _.includes(subscriptionEndpoints, pushSubscription.endpoint)) {
return;
}
this.subscribe();
});
});
I check if the current subscription is already present in the user stored endpoints, and subscribe if it isn't.
On subscription I send the new endpoint to the backend, which adds the new subscription to the user:
$.post(Routes.users_subscriptions_path({ format: 'json' }), {
subscription: subscription.toJSON()
});
Then I can send notifications to users to every endpoint:
def push_notifications_to_user(user)
message = {
title: "A message!",
tag: 'notification-tag'
}
user.notification_subscriptions.each do |subscription|
begin
Webpush.payload_send(
message: JSON.generate(message),
endpoint: endpoint,
p256dh: p256dh,
auth: auth,
api_key: public_key
)
rescue Webpush::InvalidSubscription => exception
subscription.destroy
end
end
end
The webpush gem raises an InvalidSubscription exception if the endpoint is invalid, we can destroy that endpoint to keep only the valid endpoints from the user.
The endpoint is unique by browser so you need an additional authentication scheme on the top of your app to send user's information along with the new endpoint.
You need to attach metadata (i.e. the user ID) to the endpoint when you store it on your server:
#subscription = Subscriptions.new endpoint: params[:endpoint]
#subscription.user = current_user
// or if you send with AJAX the user id together with the endpoint
#subscription.user = User.find params[:user_id]
In the second case I suggest to sign the user ID or use a secret token, otherwise anyone would be able to subscribe to push notifications as if it was another user.
Then you can delete from the database all the endpoints that belong to that user ID to unsubscribe all his devices.
However I don't think it's a good practice: a user may want to receive notifications on a device and not on another one.

Restore Access Token in hybridauth

I saved the Access Token (using this method: getAccessToken ()) in my database, but now I would like to restore this value to an object.
How can I do this?
This is explained in hybridauth user manual with below code :
// get the stored hybridauth data from your storage system
$hybridauth_session_data = get_sorted_hybridauth_session( $current_user_id );
Get_sorted_hybridauth_session is your internal function to get the stored data.
It doesnt matter whether you store the data in a table in a field named 'external_token' or something, get it through a normal sql query, and then just feed it to below function :
// then call Hybrid_Auth::restoreSessionData() to get stored data
$hybridauth->restoreSessionData( $hybridauth_session_data );
// call back an instance of Twitter adapter
$twitter = $hybridauth->getAdapter( "Twitter" );
// regrab te user profile
$user_profile = $twitter->getUserProfile();
$hybridauth->restoreSessionData( $hybridauth_session_data ); will restore the serialized session object, and then it will get an adapter for whichever provider it was saved for. Its best that you also save the provider name (Twitter in this case) in the same database table with something like external_provider , and then you can get it through a sql auery and feed it to getAdapter function. That should do what you need to do.
The manual example is below :
http://hybridauth.sourceforge.net/userguide/HybridAuth_Sessions.html
=============
As an added info - what i saw in my tests was, saving session in this way does not prevent hybridauth from logging the user in, even if the user has revoked access from the app in the meantime. Ie, if user is already logged in and authorized, but, went to the app separately and revoked the access (google for example), hybridauth will still log in the user to your system. Im currently trying to find a way to make sure the user is logged to the remote system too.
Late, but I thought this would help:
The following code verifies and removes those providers from HybridAuth that the user is not truly logged into:
$providers = $this->hybridauthlib->getConnectedProviders();
foreach( $providers as $connectedWith ){
$p = $this->hybridauthlib->getAdapter( $connectedWith );
try {
$p->getUserProfile();
} catch (Exception $e) {
$p->logout();
}
}

Resources