I have an app build on angularjs, and laravel and for authentication I use Satellizer.
Currently the login work, but it only return display name. Here is the code:
satellizer.js
providers: {
facebook: {
name: 'facebook',
url: '/auth/facebook',
authorizationEndpoint: 'https://www.facebook.com/v2.3/dialog/oauth',
redirectUri: (window.location.origin || window.location.protocol + '//' + window.location.host) + '/',
requiredUrlParams: ['scope'],
scope: ['email'],
scopeDelimiter: ',',
display: 'popup',
type: '2.0',
popupOptions: { width: 580, height: 400 }
},
account.js
angular.module('MyApp')
.factory('Account', function($http) {
return {
getProfile: function() {
return $http.get('/api/me');
},
updateProfile: function(profileData) {
return $http.put('/api/me', profileData);
}
};
});
profile.js
<div class="container">
<div class="panel panel-default">
<div class="panel-heading">Profile</div>
<div class="panel-body">
<legend><i class="ion-clipboard"></i> Edit My Profile</legend>
<form method="post" ng-submit="updateProfile()">
<div class="form-group">
<label class="control-label">Profile Picture</label>
<img class="profile-picture" ng-src="{{user.picture || 'http://placehold.it/100x100'}}">
</div>
<div class="form-group">
<label class="control-label"><i class="ion-person"></i> Display Name</label>
<input type="text" class="form-control" ng-model="user.displayName" />
</div>
<div class="form-group">
<label class="control-label"><i class="ion-at"></i> Email Address</label>
<input type="email" class="form-control" ng-model="user.email" />
</div>
<button class="btn btn-lg btn-success">Update Information</button>
</form>
</div>
</div>
auth controller in laravel php
public function facebook(Request $request)
{
$accessTokenUrl = 'https://graph.facebook.com/v2.3/oauth/access_token';
$graphApiUrl = 'https://graph.facebook.com/v2.3/me';
$params = [
'code' => $request->input('code'),
'client_id' => $request->input('clientId'),
'redirect_uri' => $request->input('redirectUri'),
'client_secret' => Config::get('app.facebook_secret')
];
$client = new GuzzleHttp\Client();
// Step 1. Exchange authorization code for access token.
$accessToken = $client->get($accessTokenUrl, ['query' => $params])->json();
// Step 2. Retrieve profile information about the current user.
$profile = $client->get($graphApiUrl, ['query' => $accessToken])->json();
// Step 3a. If user is already signed in then link accounts.
if ($request->header('Authorization'))
{
$user = User::where('facebook', '=', $profile['id']);
if ($user->first())
{
return response()->json(['message' => 'There is already a Facebook account that belongs to you'], 409);
}
$token = explode(' ', $request->header('Authorization'))[1];
$payload = (array) JWT::decode($token, Config::get('app.token_secret'), array('HS256'));
$user = User::find($payload['sub']);
dd($user);
$user->facebook = $profile['id'];
$user->displayName = $user->displayName || $profile['name'];
$user->save();
return response()->json(['token' => $this->createToken($user)]);
}
// Step 3b. Create a new user account or return an existing one.
else
{
$user = User::where('facebook', '=', $profile['id']);
if ($user->first())
{
return response()->json(['token' => $this->createToken($user->first())]);
}
$user = new User;
$user->facebook = $profile['id'];
$user->displayName = $profile['name'];
$user->save();
return response()->json(['token' => $this->createToken($user)]);
}
}
Thanks!
In a new Facebook Graph API you should include email and other things you want to get in Graph Api url, take a look at this: https://developers.facebook.com/docs/graph-api/using-graph-api/v2.5
So in your case the solution will be to update your Api urls like this:
Update:
authorizationEndpoint: 'https://www.facebook.com/v2.3/dialog/oauth',
With:
authorizationEndpoint: 'https://www.facebook.com/v2.5/dialog/oauth',
And update this:
$accessTokenUrl = 'https://graph.facebook.com/v2.3/oauth/access_token';
$graphApiUrl = 'https://graph.facebook.com/v2.3/me';
With this:
$accessTokenUrl = 'https://graph.facebook.com/v2.5/oauth/access_token';
$graphApiUrl = 'https://graph.facebook.com/v2.5/me?fields=id,name,email,picture,first_name,last_name';
Related
I'm using mean.js to create a system and I change the mongoose part for sequelize and I trying to save multiple Objects from Angular to my database through sequelize.
I followed this answer to create multiple inputs dynamically on the Dia (Day) option for multiple schedules.
And I have my controller like this:
$scope.horarios = [];
$scope.itemsToAdd = [{
Day: '',
StartHour: '',
EndHour: ''
}];
$scope.add = function(itemToAdd) {
var index = $scope.itemsToAdd.indexOf(itemToAdd);
$scope.itemsToAdd.splice(index, 1);
$scope.horarios.push(angular.copy(itemToAdd))
};
$scope.addNew = function() {
$scope.itemsToAdd.push({
Day: '',
StartHour: '',
EndHour: ''
});
console.log($scope.itemsToAdd);
};
and view
<div class="col-xs-12" style="padding: 0" ng-repeat="itemToAdd in itemsToAdd">
<div class="form-group col-xs-12 col-sm-5" >
<label for="Days">Dia</label> <select class="form-control col-xs-12 col-sm-6" data-ng-model="itemToAdd.Day" id="Days" name="Days">
<option value="">---Seleccione uno---</option>
....
</select>
</div>
<div class="form-group col-xs-5 col-sm-3">
<label class="control-label" for="startHour">Hora Inicio</label> <input class="form-control" id="startHour" name="startHour" ng-model="itemToAdd.StartHour" type="time">
</div>
<div class="form-group col-xs-5 col-sm-3">
<label class="control-label" for="endHour">Hora Termino</label> <input class="form-control" id="endHour" name="endHour" ng-model="itemToAdd.EndHour" type="time">
</div>
<div class="col-xs-2 col-sm-1">
<button ng-click="addNew()" class="btn btn-success" style="position: relative; top:26px"><i class="glyphicon glyphicon-plus"></i></button>
</div>
</div>
Then I have my both controllers on client side with Angular:
// Create new course
$scope.create = function( isValid ) {
// Create new course object
var course = new Courses( $scope.course );
course.Schedule = $scope.itemsToAdd;
console.log($scope.course);
// Redirect after save
course.$save( function( response ) {
$scope.closeThisDialog();
notify( 'Genial. El Curso ha sido registrada exitosamente' );
// Clear form fields
$scope.course = '';
$scope.schedule = '';
}, function( errorResponse ) {
$scope.error = errorResponse.data.message;
} );
};
And sequelize:
exports.create = function(req, res) {
var schedule = req.body.Schedule;
req.body.schedule = undefined;
// req.body.userId = req.user.id;
db.Course.create(req.body)
.then(function(course) {
if (!course) {
return res.send('users/signup', {
errors: 'Could not create the course'
});
} else {
schedule.CourseId = course.dataValues.id;
db.Schedule.create(schedule)
.then(function(schedule) {
for (var i = schedule.dataValues.length - 1; i >= 0; i++) {
course.schedule = schedule.dataValues[i];
}
// course.schedule = schedule.dataValues;
})
.catch(function(err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
});
return res.jsonp(course);
}
})
.catch(function(err) {
return res.status(400)
.send({
message: errorHandler.getErrorMessage(err)
});
});
};
But honestly I don't have a clue how to save it or if my Angular controller is even the correct way to do it. Hope you can help me or give me hint how to do it.
In addition to updating a single instance, you can also create, update, and delete multiple instances at once. The functions you are looking for are called
Model.bulkCreat
http://docs.sequelizejs.com/en/2.0/docs/instances/#working-in-bulk-creating-updating-and-destroying-multiple-rows-at-once
I want users to enter a username before they get to the dashboard view (if it's the first time they ever logged in) and that "Enter a unique username" will only appear once after their first login and never appear again. I'm not sure do I involve the HomeController and dashboard view(timeline) or not and whether I should just do an #if and #else statement to distinguish between username = null or not.
Home Controller:
use Auth;
class HomeController extends Controller
{
public function index()
{
if (Auth::check()) {
return view('dashboard.index');
}
return view('home');
}
}
This is my User.php:
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
protected $table = 'users';
protected $fillable = [
'username',
'first_name',
'last_name',
'email',
'password',
'location',
'gender',
'date_of_birth',
];
protected $hidden = [
'password',
'remember_token',
];
public function getName()
{
if ($this->first_name && $this->last_name) {
return "{$this->first_name} {$this->last_name}";
}
if ($this->first_name) {
return $this->first_name;
}
return null;
}
public function getUsername()
{
if ($this->first_name && $this->last_name) {
return "{$this->first_name}.{$this->last_name}";
}
if ($this->first_name) {
return $this->first_name;
}
return null;
}
public function getNameOrUsername()
{
return $this->getName() ?: $this->username;
}
public function getUsernameOrName()
{
return $this->getUsername() ?: $this->username;
}
public function getFirstNameOrUsername()
{
return $this->first_name ?: $this->username;
}
}
getusername.blade.php:
<div style="min-width: 800px; margin: 0 auto; position: relative; top: 75px;">
<div class="row" style="width: 600px; margin: 0 auto; border: 2px solid #000; padding: 40px;">
<div class="col-lg-6" style="width: 600px; color: #999; padding: 44.5px 0;">
<h3 style="color: #000; margin-top: 0; margin-bottom: 10px;">Enter a username</h3>
<form class="form-vertical" role="form" method="post" action="{{ route('dashboard.getusername') }}">
<div>
<div>Your public username is the same as your Profile address:
<div>
<ul>
<li>
<div>mostwanted.com/<span id="display_name">
<script>
$('#username').keyup(function () {
$('#display_name').text($(this).val());
});
</script>
</span></div>
</li>
</ul>
</div>
</div>
<div class="form-group {{ $errors->has('username') ? ' has-error' : '' }}">
<label for="username" class="control-label">Choose a username</label>
<input style="width: 456px;" placeholder="e.g. {{ Auth::user()->getUsernameOrName() }}" type="text" name="username" class="form-control" id="username" value="">
#if ($errors->has('username'))
<span class="help-block" style="font-size: 12px; margin-bottom: 0;">{{ $errors->first('username') }}</span>
#endif
</div>
<div>Note: Your username cannot be changed and should include your authentic name </div>
</div>
</div>
<div class="form-group" style="margin-top: 15px;">
<button style="float: right;" type="submit" class="btn btn-primary">Save username</button>
</div>
<input type="hidden" name="_token" value="{{Session::token()}}">
</form>
</div>
</div>
UsernameController:
use Auth;
use DB;
use MostWanted\Models\User;
use Illuminate\Http\Request;
class UsernameController extends Controller
{
public function getUsername()
{
return view('dashboard.getusername');
}
public function postUsername(Request $request)
{
$username = Auth::user()->username;
if (!$username) {
return view('dashboard.getusername');
}
$this->validate($request, [
'username' => 'required|unique:users|regex:/^[A-Za-z0- 9.]+$/|max:50',
]);
User::create([
'username' => $request->input('username'),
]);
return view('dashboard.index');
}
}
The last time I did it was #if (Auth::user()->username===null) it only goes to the form for entering a username even if I've entered a username already (redirect to the username form only).
P.S I have no idea why the <script> doesn't work. I want the <span> to display whatever is being entered in the <input>
EDIT*:
routes.php:
/**
*Home + Entering Username
*/
Route::get('/', [
'uses' => '\MostWanted\Http\Controllers\HomeController#index',
'as' => 'home',
]);
Route::get('/', ['middleware' => 'nousername', function () {
[
'uses' => '\MostWanted\Http\Controllers\UsernameController#getUsername',
'as' => 'dashboard.getusername',
];
[
'uses' => '\MostWanted\Http\Controllers\UsernameController#postUsername',
];
}]);
Route::group(['middleware' => ['web']], function () {
/**
*Authenication
*/
#Sign up
Route::get('/signup', [
'uses' => '\MostWanted\Http\Controllers\AuthController#getSignup',
'as' => 'auth.signup',
'middleware' => ['guest'],
]);
Route::post('/signup', [
'uses' => '\MostWanted\Http\Controllers\AuthController#postSignup',
'middleware' => ['guest'],
]);
#Log in
Route::get('/login', [
'uses' => '\MostWanted\Http\Controllers\AuthController#getSignin',
'as' => 'auth.signin',
'middleware' => ['guest'],
]);
Route::post('/login', [
'uses' => '\MostWanted\Http\Controllers\AuthController#postSignin',
'middleware' => ['guest'],
]);
#Log out
Route::get('/logout', [
'uses' => '\MostWanted\Http\Controllers\AuthController#getSignOut',
'as' => 'auth.signout',
]);
/**
*Search
*/
Route::get('/search', [
'uses' => '\MostWanted\Http\Controllers\SearchController#getResults',
'as' => 'search.results',
]);
/**
*User profile
*/
Route::get('/user/{username}', [
'uses' => '\MostWanted\Http\Controllers\ProfileController#getProfile',
'as' => 'profile.index',
]);
});
NoUsernameMiddleware:
namespace MostWanted\Http\Middleware;
use Auth;
use Closure;
class NoUsernameMiddleware
{
public function handle($request, Closure $next) {
if(!Auth::user()->username) {
return redirect("/choose_username");
}
return $next($request);
}
}
You should use is_null function to test your username
Can you give us the controller's method associated to route('dashboard.getusername') ? Maybe the form works but the username is not saved in database
I suggest you to handle this case with a middleware.
To create one, open the shell in the root of your project and type:
php artisan make:middleware NoUsernameMiddleware
A file called NoUsernameMiddleware.php will be created in app/Http/Middleware/; open it and add these lines in the handle function.
public function handle($request, Closure $next)
{
if(!Auth::user()->username){
return redirect("/path/to/username/input")
}
return $next($request);
}
Register it in app/Http/Kernel.php.
protected $routeMiddleware = [
...,
...,
'nousername' => \App\Http\Middleware\AgeMiddleware::class,
];
Apply the middleware to the dashboard route:
Route::get('/dashboard', ['middleware' => 'nousername', function () {
//
}]);
Then you can create the Controller and the view to handle the form where all of users without an username will be redirected to.
I am very much new in AngularJS and I have the following problem:
View:
<div>
<form role="form" name="loginForm" class="form-horizontal login-form">
<div class="form-group">
<p class="login-form-msg">Welcome : {{user.username}}</p>
<label for="inputUserName" class="col-sm-2 control-label login-form-label">Base</label>
<div class="col-sm-10">
<input type="text" placeholder="Enter base" class="form-control" required ng-model="user.code">
</div>
</div>
<div class="form-group">
<label for="inputUserName" class="col-sm-2 control-label login-form-label">Username</label>
<div class="col-sm-10">
<input type="text" placeholder="Enter name" class="form-control" required ng-model="user.username">
</div>
</div>
<div class="form-group">
<label for="inputPassword" class="col-sm-2 control-label login-form-label">Password</label>
<div class="col-sm-10">
<input type="password" placeholder="Password" id="inputPassword" class="form-control" required ng-model="user.password">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10 login-form-button">
<button class="btn btn-default" type="submit" ng-disabled="loginForm.$invalid" ng-click="login(user)">Sign in</button>
</div>
<p class="login-form-msg">{{msgtxt}}</p>
</div>
</form>
</div>
Main js:
var myApp = angular.module('myApp', ['ngRoute']);
myApp.config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/login', {
templateUrl: 'partials/login.html',
controller:'loginCtrl'
});
$routeProvider.when('/welcome', {
templateUrl: 'partials/welcome.html',
controller:'loginCtrl'
});
$routeProvider.otherwise({ redirectTo: '/login' });
}]);
I have the following factory:
myApp.factory('getURLService', function ($http, config) {
return {
getURL: function (user,scope) {
$http.get(config.backend + "/Device/GetURLbyCode", {
params: { code: user.code }
})
.success(function (data) {
var url = '';
if (data.status == 'succ') {
url = data.Result;
}
else {
scope.msgtxt = data.msg;
}
return url;
});
}
}
});
I need to use the returned value from this factory in other factories.
For example in my login factory:
myApp.factory('loginService', function ($http, $location, config) {
return {
login: function (user,url,scope) {
$http.get(url + "/Device/Register", {
params: { userName: user.username, password: user.password }
})
.success(function (data) {
if (data.status == 'succ') {
$location.path('/welcome');
}
else {
scope.msgtxt = data.msg;
}
});
}
}
});
This is my controller:
myApp.controller('loginCtrl', function ($scope, getURLService, loginService) {
$scope.msgtxt = '';
$scope.login = function (user) {
loginService.login(user,url,$scope); //call login service
}
});
What do I need to do in my controller to actually return the url and then send it to the login service or any other service (or even controller) in the future?
Thanks in advance for your time and suggestion.
For returning data from the function you should return promise object which $http.get already returns it.
Additional thing which I wanted to point out is, passing $scope to the service disobey the rule of singleton, as you are creating a service which is dependent of the controller scope. Service should only accept the parameter and return the result by processing it, nothing else.
Code
return {
getURL: function (user,scope) {
return $http.get(config.backend + "/Device/GetURLbyCode", {
params: { code: user.code }
})
.then(function (res) {
var data = res.data;
var url = '';
if (data.status == 'succ') {
url = data.Result;
}
else {
scope.msgtxt = data.msg;
}
return url;
});
}
}
LoginService
myApp.factory('loginService', function ($http, $location, config) {
return {
login: function (user,url) {
return $http.get(url + "/Device/Register", {
params: { userName: user.username, password: user.password }
})
.then(function (response) {
var data = response.data;
if (data.status == 'succ') {
$location.path('/welcome');
return;
}
return data.msg;
});
}
}
});
Controller
getURLService.getURL(user).then(function(url){
//assuming you already having value of user available here
loginService.login(user,url).then(function(message){ //call login service
if(message)
$scope.msgtxt = message;
});
});
I'm trying to add a signup function, using a controller and a factory, to my Angular app, but I haven't been able to get several strings (tied conditionally to success or failure) to return from my factory to my controller.
The return statements below only return empty strings at first (I assume this has to do with the asynchronous http, but am not sure). In any case, how would I return the two strings I desire (_alertType and _alertMessage) with the updated values from .success or .error?
signup.html
<div class="col-md-6 container-fluid">
<div class="jumbotron text-center" ng-controller="SignupController as vm">
<p class="lead">
<h2>Account Creation</h2>
Welcome! Please make an account
</p>
<form ng-submit="vm.signup()">
<p><input type="text" name="username" value="" placeholder="Username or Email" ng-model="username"></p>
<p><input type="password" name="password" value="" placeholder="Password" ng-model="password"></p>
<p class="submit"><input type="submit" name="commit" value="Sign Up"></p>
<alert ng-show="vm.alertMessage" type="{{ vm.alertType }}">{{ vm.alertMessage }}</alert>
</form>
</div>
</div>
signup.factory.js
(function() {
angular
.module('app')
.factory('signupFactory', signupFactory);
signupFactory.$inject = ['$http'];
function signupFactory($http) {
var _alertType = '';
var _alertMessage = '';
var service = {
signup: signup,
getAlertType: getAlertType,
getAlertMessage: getAlertMessage
};
return service;
function signup(username, password) {
var request = $http({
method: 'POST',
url: 'http://localhost:8080/user',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
data: {
username: username,
password: password
}
});
request.success(function(){
_alertType = "success";
_alertMessage = "Signed Up";
});
request.error(function(){
_alertType = "danger";
_alertMessage = "Signup Failed";
});
}
function getAlertType() {
return _alertType;
}
function getAlertMessage() {
return _alertMessage;
}
}
})();
signup.controller.js
(function() {
'use strict';
angular
.module('app')
.controller('SignupController', SignupController);
SignupController.$inject = ['$scope', 'signupFactory'];
function SignupController($scope, signupFactory) {
var vm = this;
vm.signup = function() {
signupFactory.signup($scope.username, $scope.password);
vm.alertMessage = signupFactory.getAlertMessage();
vm.alertType = signupFactory.getAlertType();
}
}
})();
You should look for promises
var promise = asyncGreet('Robin Hood');
promise.then(function(greeting) {
alert('Success: ' + greeting);
}, function(reason) {
alert('Failed: ' + reason);
});
At the moment I have javascript that allows all users from the (_User) table to log in. I have set up a Role called (Admins) within the role table and assigned one user to this role. Would this be an if statement?
At the moment this is how the user logs in successfully
$scope.logIn = function(form) {
Parse.User.logIn(form.username, form.password, {
success: function(user) {
$scope.currentUser = user;
$scope.$apply();
window.location.href = "TEST.html";
},
It's easy to check whether any user belongs to a role. The only tricky part is to realize that the check includes a query, and is therefore an asynchronous operation. So first, a general purpose role checking function:
function userHasRole(user, roleName) {
var query = new Parse.Query(Parse.Role);
query.equalTo("name", roleName);
query.equalTo("users", user);
return query.find().then(function(roles) {
return roles.length > 0;
});
}
This returns a promise that will be fulfilled with a boolean, so you can call it like this:
var currentUser = Parse.User.current();
// is the user an "admin"?
userHasRole(currentUser, "admin").then(function(isAdmin) {
console.log((isAdmin)? "user is admin" : "user is not admin");
});
Apply it like this in your code. In the view:
<form role="form" name="loginForm">
<div class="form-group">
<label>Email</label>
<input type="email" class="form-control" name="email" ng-model="user.username" />
</div>
<div class="form-group">
<label>Password</label>
<input type="password" class="form-control" name="password" ng-model="user.password" />
</div>
<div class="form-group">
<button class="btn btn-ar btn-primary" ng-click="pressedLogIn()">Log in</button>
</div>
</form>
And in the controller:
(function() {
'use strict';
angular.module('myApp.controllers').controller('LogInController', LogInController);
LogInController.$inject = ['$scope'];
function LogInController($scope) {
$scope.user = { username:"", password:""};
function userHasRole(user, roleName) {
// defined exactly as above
// my real app has a user service, and this would be better placed there
}
$scope.pressedLogIn = function() {
if ($scope.loginForm.$valid) {
Parse.User.logIn($scope.user.username, $scope.user.password).then(function(user) {
$scope.user = user;
return userHasRole(user, "administrator");
}).then(function(isAdmin) {
alert("user is admin = " + isAdmin);
}, function(e) {
alert(error.message);
});
}
};
}
})();