In my quest to learn the MEAN stack i'm building a small multi tenanted app and struggling with getting my users / tenants all signed up. Backend is sorted I believe just cant quite figure out how to get angular to play ball.
Flow... User signs up a new account, Which concurrently creates a new tenant. Like so...
var express = require('express');
var router = express.Router();
var bcrypt = require('bcryptjs');
var Tenant = require('../models/tenant');
var User = require('../models/user');
router.post('/', function (req, res, next) {
var tenant = new Tenant({
name: req.body.name
});
tenant.save(function(err, tenant) {
Tenant.findById(tenant._id, function(err, tenant) {
var user = new User({
first_name: req.body.first_name,
last_name: req.body.last_name,
email: req.body.email,
password: bcrypt.hashSync(req.body.password, 10),
active: req.body.active,
tenant: tenant
})
user.save(function (err, user) {
if (err) {
return res.status(500).json({
title: 'An error has occured',
error: err
});
}
res.status(201).json({
message: 'User created',
obj: user
});
})
});
});
// tenant.findByIdAndUpdate(tenant._id, {owner: user._id});
});
module.exports = router;
This, for the most part, works as intended. At least in testing with postman.
In angular my signup component (in its working state before I tried introducing tenants) looks like:
import { Component, OnInit } from '#angular/core';
import {FormControl, FormGroup, Validators} from "#angular/forms";
import {Router} from "#angular/router";
import {AuthService} from "../auth.service";
import {User} from "../user.model";
import {Tenant} from "../tenant.model";
#Component({
selector: 'app-signup',
templateUrl: './signup.component.html',
styleUrls: ['./signup.component.css']
})
export class SignupComponent implements OnInit{
myForm: FormGroup;
constructor(private router: Router, private authService: AuthService) {}
onSubmit() {
const user = new User(
this.myForm.value.first_name,
this.myForm.value.last_name,
this.myForm.value.email,
this.myForm.value.password
);
this.authService.signup(user)
.subscribe(
data => console.log(data),
error => console.error(error)
);
this.router.navigate(['/signup/success/' + this.myForm.value.email]);
}
ngOnInit() {
this.myForm = new FormGroup({
coName: new FormControl('', Validators.required),
email: new FormControl('', Validators.required),
password: new FormControl('', Validators.required),
active: new FormControl(true, Validators.required)
});
}
}
and my AuthService (again in its working state before i tried introducing tenants) ...
import { Injectable } from "#angular/core";
import { Http, Headers, Response } from "#angular/http";
import 'rxjs/Rx';
import { Observable } from "rxjs";
import { User } from "./user.model";
import { Tenant } from "./tenant.model";
#Injectable()
export class AuthService {
constructor(private http: Http) {}
signup(user: User) {
const body = JSON.stringify(user);
const headers = new Headers({'Content-Type': 'application/json'});
return this.http.post('/api/tenant', body, {headers: headers})
.map((response: Response) => response.json())
.catch((error: Response) => Observable.throw(error.json()));
}
signin(user: User) {
const body = JSON.stringify(user);
const headers = new Headers({'Content-Type': 'application/json'});
return this.http.post('/api/user/signin', body, {headers: headers})
.map((response: Response) => response.json())
.catch((error: Response) => Observable.throw(error.json()));
}
logout() {
localStorage.clear();
}
isLoggedIn() {
return localStorage.getItem('token') !== null;
}
}
Now, i'm not looking for a handout, or anyone to write this for me... just a friendly nudge in the right direction, if that's allowed on here ;) . Would it be easier to just abandon the reactive form and use ngModel? Or perhaps, define a new angular model that is a hybrid of user/tenant?
Cheers.
In case anyone sees this and cares... I was putting a level of importance on my angular models mimicking my mongoose models. I ended up creating a new angular model (signup.model.ts) made up of the relevant fields from both my tenant and user mongoose models. Now I'm not sure this was necessarily the ideal way to structure this, however it works so feel I can put it in as an answer.
Cheers.
Related
I am trying to send current logged in username from django backend to React frontend. I have created an endpoint currentuser/ that works perfectly fine in backend, it returns the expected result but when I call this api endpoint in React using axios,null value is returned there.
Here's the code for backend
#view.py
from django.contrib.auth import get_user_model
from rest_framework import serializers
from rest_framework.response import Response
from rest_framework.views import APIView
User = get_user_model()
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username')
class LoggedInUserView(APIView):
def get(self, request):
serializer = UserSerializer(request.user)
return Response(serializer.data)
#urls.py
urlpatterns = [
path('currentuser/', views.LoggedInUserView.as_view(), name='currentuser'),
]
Here's the result when calling the api directly
Here's the code for frontend
class App extends React.Component {
state = {
users: [],
}
getUsers() {
axios.defaults.headers.common['Content-Type'] = 'application/json';
axios.get(`http://localhost:8000/currentuser/`)
.then(res => {
console.log("res :", res);
const user = res.data;
console.log("response from backend", user);
this.setState({ users: user });
console.log(this.state.users);
})
.catch(err => {
console.log("error:", err);
});
console.log(this.state.users);
}
constructor(props) {
super(props);
this.getUsers();
}
render() {
return (.....)
}
};
export default App;
Here's the result when calling the api from the frontend
Any suggestions would be appreciated
Just learning this topic now. Did you login on React front-end? If you just want to retrieve login user's profile.
Here is my solution for your reference.
Firstly, I tried use simple-JWT authentication to set up react and Django.
(google "JWT authentication Django and React", there are many many teaching materials).
Then to log in on react site, and from a response of Django you can retrieve the logged-in user detail. The response.data is a token, which means you can use a "jwt_decode" to get the information you want including: username, id, email. (may have security issue... refer to If you can decode JWT, how are they secure?, just for learning should be fine).
Your code might look like the following:
axios.post("http://127.0.0.1:8000/token/", {
username: username,
password: password,
})
.then((response) => {
let token = response.data.access;
localStorage.setItem("token", token);
let user_id = jwt_decode(response.data.access).user_id;
...
localStorage.setItem("user_id", user_id);
})
Once you got your user_id in localstorage, you can use it to retrieve all the details, your code might look like:
let id = parseInt(localStorage.getItem("user_id"));
const userDetail = (id) => {
const token = localStorage.getItem("token");
axios
.get(`http://127.0.0.1:8000/users/${id}`, {
headers: { Authorization: token },
})
.then(function (response) {
console.log(response.data);
})
.catch(function (error) {
console.log(error);
});
The response.data includes all information you posted on your Django back-end API.
Hope this helped.
I have added a axios interceptor within which authProvider.getAccessToken() is called to fetch token and add to header of each request.
Here is my axiosInterceptor.js
import axios from 'axios'
import { authProvider } from '../authProvider'
export const axiosApiIntance = axios.create()
export const axiosInterceptor = axiosApiIntance.interceptors.request.use(async request => {
try {
let token = await authProvider.getAccessToken()
request.headers['Authorization'] = `Bearer ${token.accessToken}`
return request
} catch (err) {
console.log(err)
}
}, error => {
return Promise.reject(error.message)
})
Here is my authProvider.js
import { LoginType, MsalAuthProvider } from 'react-aad-msal'
// The auth provider should be a singleton. Best practice is to only have it ever instantiated once.
// Avoid creating an instance inside the component it will be recreated on each render.
// If two providers are created on the same page it will cause authentication errors.
export const authProvider = new MsalAuthProvider(
{
auth: {
authority: process.env.REACT_APP_AUTHORITY,
clientId: process.env.REACT_APP_CLIENT_ID,
postLogoutRedirectUri: process.env.REACT_APP_URL,
redirectUri: process.env.REACT_APP_URL,
validateAuthority: true,
// After being redirected to the "redirectUri" page, should user
// be redirected back to the Url where their login originated from?
navigateToLoginRequestUrl: false
},
cache: {
cacheLocation: 'sessionStorage',
storeAuthStateInCookie: true
}
},
{
scopes: ['openid', 'profile', 'user.read']
},
{
loginType: LoginType.Redirect,
// When a token is refreshed it will be done by loading a page in an iframe.
// Rather than reloading the same page, we can point to an empty html file which will prevent
// site resources from being loaded twice.
tokenRefreshUri: window.location.origin + '/auth.html'
}
)
authProvider is used in App.js
<AzureAD provider={authProvider} reduxStore={configureStore}>
....
</AzureAD>
axiosInterceptor is also included in App.js.
Please provide suggestion on what could cause the component the reload indifinitely.
I have removed the authProvider.getAccessToken() and verified, it works fine. So the reload is caused due to that.
First, I suggest you to verify the Scope, authority and clientId of your AuthProvider.
I had a similar issue in one project ans I had to add the scope to the getAccessToken() function, even if I never did that in others projects..
See below:
var authenticationParameters = {
scopes: ['openid', 'profile', 'user.read'],
};
axios.interceptors.request.use(function (config): any {
return new Promise(async (resolve: any, reject: any) => {
await authProvider.getAccessToken(authenticationParameters).then((response: any) => {
config.headers["Authorization"] = "Bearer " + response.accessToken;
config.headers["Content-Type"] = "application/json";
config.headers.Accept = "application/json";
resolve(config);
})
.catch((error: any) => {
console.log(error.message);
});
});
});
Hope it help ;)
Regards
I am using the authorize.net payment gateway in the Ionic framework.
I am using this acceptjs-angular-wrapper
and I am following this Tutorial
Here is my code:
home.page.html
<ion-header [translucent]="true">
<ion-toolbar>
<ion-title>
Payment
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content [fullscreen]="true">
<ion-button
class="AcceptUI payButton"
id="AcceptUI"
data-billingAddressOptions='{"show":true, "required":true}'
[attr.data-apiLoginID]="apiLoginID" [attr.data-clientKey]="clientKey"
data-acceptUIFormHeaderTxt="Card Information"
data-acceptUIFormBtnTxt="Submit"
data-paymentOptions='{"showCreditCard": true, "showBankAccount": true}'
data-responseHandler="responseHandler"
>
Pay ${{ amount }}
</ion-button>
<ion-button (click)="loadIframe()">Load</ion-button>
</ion-content>
home.page.ts
import { Component } from '#angular/core';
import { NavController } from '#ionic/angular';
import { WebService } from './../web.service';
#Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage {
public apiLoginID = 'xxxxx';
public clientKey = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
public transactionKey = 'xxxxxxxxxxxxxxxx';
public amount = '5';
constructor(
private webService: WebService,
private navCrtl: NavController
) { }
ionViewWillEnter() {
setTimeout(() => {
const s = document.createElement('script');
s.type = 'text/javascript';
s.innerHTML = 'console.log(\'done\');'; // inline script
s.src = 'https://jstest.authorize.net/v3/AcceptUI.js';
s.charset = 'utf-8';
document.querySelector('head').appendChild(s);
}, 1000);
document.removeEventListener('notification', () => { console.log('Removed!!'); });
const buttonElement = document.getElementById('AcceptUI');
buttonElement.addEventListener('notification', (response: any) => {
event.stopPropagation();
event.preventDefault();
// Call your api here and pass the opaque data in backend
this.paymentHandler(response.detail.opaqueData);
document.removeEventListener('notification', () => { console.log('Removed!!'); });
}, false);
}
paymentHandler(payData: any) {
console.log(payData);
// Put you api here to capture the payment data
const data = {
createTransactionRequest: {
merchantAuthentication: {
name: this.apiLoginID,
transactionKey: this.transactionKey
},
transactionRequest: {
transactionType: 'authCaptureTransaction',
amount: this.amount,
payment: {
opaqueData: payData
}
}
}
};
this.webService.paymentHandler(data).then((response) => {
console.log('API', response);
alert(JSON.stringify(response));
}).catch((error) => {
console.log(error);
})
}
}
// To handle response form authorize.net api
window['responseHandler'] = function responseHandler(response) {
console.log('ok');
console.log('responseHandler', response);
if (response.messages.resultCode === 'Ok') {
const event = new CustomEvent('notification', { detail: response });
const buttonElement = document.getElementById('AcceptUI');
buttonElement.dispatchEvent(event);
}
if (response.messages.resultCode === 'Error') {
let i = 0;
while (i < response.messages.message.length) {
console.log(
response.messages.message[i].code + ': ' +
response.messages.message[i].text
);
i = i + 1;
}
};
};
web.service.ts
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class WebService {
constructor(private http: HttpClient) {
console.log('Hello WebServiceProvider Provider');
}
paymentHandler(data) {
return new Promise((resolve, reject) => {
this.http.post('https://apitest.authorize.net/xml/v1/request.api', data)
.subscribe(resp => {
console.log(resp);
resolve(resp);
}, (err) => {
reject(err);
})
});
}
}
I want to show recent cards like this:
I want to load the payment method like the above image.
I am currently getting this view in my app:
If anyone has questions or wants more details then please comment.
From the "Integrating the Hosted Payment Information Form" section from the documentation, there is no optionto pass the profile ID to the hosted form using Accept.js.
For this, you can follow the Accept Hosted documentation to add this functionality.
From the documentation:
Call getHostedPaymentPageRequest to request a form token. This request contains transaction information and form parameter settings.
Embed the payment form or redirect the customer to the payment form by sending an HTML POST containing the form token to
https://accept.authorize.net/payment/payment.
Your customer completes and submits the payment form. The API sends the transaction to Authorize.net for processing. The customer is
returned to your site, which displays a result page based on the URL
followed or the response details sent.
I believe that you can use the redirect option to redirect the user to the Authorize.net page. You can do it by using the In App Browser plugin to open another webview and go to new webpage.
I have do connection in 'Angular6' using sqlserver.
server.js
var express = require('express');
var app = express();
app.get('/', function (req, res) {
var sql = require("mssql");
// config for your database
var config = {
user: 'abc',
password: 'abc',
server: 'servername',
database: 'xyz'
};
// connect to your database
sql.connect(config, function (err) {
if (err) console.log(err);
// create Request object
var request = new sql.Request();
// query to the database and get the records
request.query('select * from tbl', function (err, recordset) {
if (err) console.log(err)
// send records as a response
res.send(recordset);
});
});
});
var server = app.listen(5000, function () {
console.log('Server is running..');
});
data.service.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class DataService {
constructor(private http: HttpClient) { }
getUsers() {
return this.http.get('https://jsonplaceholder.typicode.com/users')
}
getUser(userId) {
return this.http.get('https://jsonplaceholder.typicode.com/users/'+userId)
}
getPosts() {
return this.http.get('https://jsonplaceholder.typicode.com/posts')
}
getPhotos()
{
return this.http.get('https://jsonplaceholder.typicode.com/photos');
}
getTodos()
{
return this.http.get('https://jsonplaceholder.typicode.com/todos');
}
}
Right now I have used dummy API'S for result.
how to get my database results in service?
I have successfully get result from Sqlserver database.
I also want to display record in my Component
user.component.html
<h1>Users</h1>
Can I have to import server.js in user.component.ts.
If yes than how can I do that?
I think you are misunderstanding angular. Angular run into browser and its context is limited to that.
If you need to connect to a database, you need to use some backend technologies, like express and nodejs, as the code you posted.
The main way is to expose some backend services, like REST services, developed with a server side techonology (nodejs, j2ee, php, etc) and then use Angular to ask them for data.
Generally to achieve this goal in angular you should use HttpClient
You should search for a tutorial, like this
Angular example to request data
In angular you should create a service class to call your exposed service, then into that class you could create a method like this:
import {HttpClient, HttpHeaders} from '#angular/common/http';
import {Observable} from 'rxjs';
import {Injectable} from '#angular/core';
import {catchError, map, tap} from 'rxjs/operators';
#Injectable({
providedIn: 'root'
})
export class TestService {
get(): Observable<any> {
return this.http.get([YOUR_BACKEND_SERVICE_URL]).pipe(
catchError(this.handleError(`get`))
);
}
private handleError<T>(operation = 'operation', result?: T) {
return (error: any): Observable<T> => {
console.error(error);
this.log(`${operation} failed: ${error.message}`);
return of(result as T);
};
}
}
Then you should write a component like this:
#Component({
selector: 'app-test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.css']
})
export class TestComponent implements OnInit {
data: any;
constructor(private testService: TestService) { }
ngOnInit() {
this.getData();
}
getData(): void {
this.testService.get().subscribe(data => console.log(data));
}
}
You need to create service and component with AngularCli in order to avoid to manually declare and import them into app.module.ts
For a better understanding of what is happening I suggest you to read Angular Tour of Heroes tutorial, Services section
I need to connect orientDB with my angularJS login web application.
after log in user allowed to iput some data to web application and those data also need to be stored in the orient DB data base .
So i need to connect database with my angularJS web application and to use database to store and retrieve data,
This is a sample Angular2 service to connect to OrientDB
import {Injectable} from "#angular/core";
import {Headers, Http} from '#angular/http';
#Injectable()
export class OrientService {
url = "http://localhost:2480/command/yourDbName/"
username = "admin";
password = "admin";
constructor(private http: Http) {
}
command(statement: string, success: (data: any) => void, error: (err: any) => void): void {
var url = this.url + "sql/-/-1"
var headers = new Headers();
headers.append("Authorization", "Basic " + btoa(this.username + ":" + this.password));
this.http.post(url,
JSON.stringify({"command": statement}),
{headers: headers})
.toPromise()
.then(success)
.catch(error);
}
}
Then you can use it as follows:
this.orientService.command(
"SELECT FROM V",
(res) => {
let body = res.json();
...
},
(e) => {
console.log(e)
});
Here you can find a full example: https://github.com/luigidellaquila/geospatial-demo/tree/geeconprague2016
Consider that you will have to enable cross-site requests in OrientDB https://orientdb.com/docs/2.2/Web-Server.html