i have a strange problem:
we have to make a project in IT, therefore we use AngularJS.
The problem is, when I use F5 for refresh, the page loads, but it is not able to show the right content again. There's just background and my title, everything in my UI-VIEW isn't there.
We have Login-Page with redirecting:
app.run(function($rootScope, $location, sessionFactory) {
$rootScope.$on('$stateChangeStart',
function(event, toState, toParams, fromState, fromParams){
let loggedIn = sessionFactory.isAuthenticated();
if (toState.authenticate && !loggedIn) {
event.preventDefault();
$state.go('login');
}
});
});
without this redirecting block, F5 works.
Otherwise I have to go to Login-Page and login again to get it work again.
I'm sorry guys, I'm new at programming. So if there's any code you need, just let me know. Hope someone can help.
UPDATE: this is our authentification_service.js
a group member wrote it. Does it help?
var app = angular.module('TheApp');
/**
* This service manages sessions: Retrieving token from server and storing token data.
*/
app.factory('sessionFactory', ['$http', 'jwtDecoder', function($http, jwtDecoder) {
var sessionFactory = {
sessionData: null
};
sessionFactory.login = function(username, password) {
//todo: encrypt password....
var user = { username : username, password : password};
// returns a POST request, success or error of that request
// must be handled by the caller of the login function
return $http({
method: 'POST',
url: 'rest/auth/login',
data: user
});
};
sessionFactory.logout = function() {
return $http({
method: 'POST',
url: 'rest/auth/logout',
data: this.sessionData
});
}
sessionFactory.deleteSessionData = function() {
this.sessionData = null;
}
sessionFactory.setSessionData = function(sessionData) {
this.sessionData = {
token: sessionData.token,
userData: jwtDecoder.getUserData(sessionData.token) // holds user id, todo: permissions
};
console.log(this.sessionData.userData);
};
sessionFactory.getToken = function() {
return this.sessionData.token;
};
sessionFactory.getUserId = function() {
return this.sessionData.userData.userId;
}
sessionFactory.isAuthenticated = function() {
return this.sessionData != null;
};
return sessionFactory;
}]);
/**
* This service injects authentification token in HTTP requests.
*/
app.factory('tokenInjector', ['$injector', function($injector) {
var tokenInjector = {
request: function(config) {
// cannot use sessionFactory directly, because else Angular will spot a circular dependency -> error
var sessionFactory = $injector.get('sessionFactory');
// if the user is logged in, add an Authorization header (with token) to each http request
if(sessionFactory.isAuthenticated()) {
config.headers.Authorization = 'Bearer ' + sessionFactory.getToken();
//config.url = config.url + "?token=" + sessionFactory.getToken(); // add token to request url
}
return config;
}
};
return tokenInjector;
}]);
/**
* Decodes JWTs received from the server with a JWT deconding lib
* and returns a useable result.
*/
app.factory('jwtDecoder', function() {
var jwtDecoder = {};
// extracts all needed frontend user data from token
jwtDecoder.getUserData = function(token) {
var payload = jwt_decode(token);
var userData = {
userId: payload.userId //,
//groupId: ?,
//permissions: payload.permissions, // is array of perm
};
return userData;
}
return jwtDecoder;
})
Related
I am trying to send a notification whenever a new update to my database takes place. I have the onUpdate side working but I am new to FCM and I am stuck at the sending the notification.
The structure of the devices collection is:
+devices/
+tokenId/
-tokenId:njurhvnlkdnvlksnvlñaksnvlkak
-userId:nkjnjfnwjfnwlknlkdwqkwdkqwdd
The function that I have right now that gets stuck with an empty value of token is:
const functions = require('firebase-functions');
const admin = require("firebase-admin");
admin.initializeApp();
const db = admin.firestore();
const settings = { timestampsInSnapshots: true };
db.settings(settings);
.....
exports.fcmSend = functions.firestore
.document(`chats/{chatId}`).onUpdate((change, context) => {
const messageArray = change.after.data().messages;
const message = messageArray[(messageArray.length-1)].content
if (!change.after.data()) {
return console.log('nothing new');
}
const payload = {
notification: {
title: "nuevo co-lab",
body: message,
}
};
return admin.database().ref(`/devices`)
.once('value')
.then(token => token.val())
.then(userFcmToken => {
console.log("Sending...", userFcmToken);
return admin.messaging().sendToDevice(userFcmToken, payload)
})
.then(res => {
console.log("Sent Successfully", res);
})
.catch(err => {
console.log("Error: ", err);
});
});
I am not able to get the token from the database. It is null or undefined. Can anyone help me with this second part of the function?
Thanks a lot in advance!
Thanks Frank for the tip!
I managed to solve the problem with this code in case anybody needs it:
const payload = {
notification: {
title: "nuevo mensaje de co-lab",
body: message,
}
};
// Get the list of device tokens.
const allTokens = await admin.firestore().collection('devices').get();
const tokens = [];
allTokens.forEach((tokenDoc) => {
tokens.push(tokenDoc.id);
});
if (tokens.length > 0) {
// Send notifications to all tokens.
return await admin.messaging().sendToDevice(tokens, payload);
}else {
return null;
}
How do i selete an object in a bucket through a jQuery-Call. The following Code shows my example for uploading the file. The goal is to have the deleting in a similar way. Thanks
function uploadFile(node) {
$('#hiddenUploadField').click();
$('#hiddenUploadField').change(function () {
if (this.files.length == 0) return;
var file = this.files[0];
switch (node.type) {
case 'bucket':
var formData = new FormData();
formData.append('fileToUpload', file);
formData.append('bucketKey', node.id);
$.ajax({
url: '/api/forge/oss/objects',
data: formData,
processData: false,
contentType: false,
type: 'POST',
success: function (data) {
$('#appBuckets').jstree(true).refresh_node(node);
}
});
break;
}
});
}
You could expose the necessary part on the server side (just like it is done for the /api/forge/oss/objects endpoint which uploads a file to a given bucket) which then could be called from the client side in a similar way.
Server side:
router.delete('/buckets/:id', function (req, res) {
var tokenSession = new token(req.session)
var id = req.params.id
var buckets = new forgeSDK.BucketsApi();
buckets.deleteBucket(id, tokenSession.getOAuth(), tokenSession.getCredentials())
.then(function (data) {
res.json({ status: "success" })
})
.catch(function (error) {
res.status(error.statusCode).end(error.statusMessage);
})
})
Client side:
function deleteBucket(id) {
console.log("Delete bucket = " + id);
$.ajax({
url: '/dm/buckets/' + encodeURIComponent(id),
type: 'DELETE'
}).done(function (data) {
console.log(data);
if (data.status === 'success') {
$('#forgeFiles').jstree(true).refresh()
showProgress("Bucket deleted", "success")
}
}).fail(function(err) {
console.log('DELETE /dm/buckets/ call failed\n' + err.statusText);
});
}
Have a look at this sample which has both file upload and bucket deletion implemented: https://github.com/adamenagy/oss.manager-nodejs
Ah great, thank you. And how would you solve it on the server side with C# ? Rigth now the Upload on server-side looks like:
[HttpPost]
[Route("api/forge/oss/objects")]
public async Task<dynamic> UploadObject()
{
// basic input validation
HttpRequest req = HttpContext.Current.Request;
if (string.IsNullOrWhiteSpace(req.Params["bucketKey"]))
throw new System.Exception("BucketKey parameter was not provided.");
if (req.Files.Count != 1)
throw new System.Exception("Missing file to upload");
string bucketKey = req.Params["bucketKey"];
HttpPostedFile file = req.Files[0];
// save the file on the server
var fileSavePath = Path.Combine(HttpContext.Current.Server.MapPath("~/App_Data"),
file.FileName);
file.SaveAs(fileSavePath);
// get the bucket...
dynamic oauth = await OAuthController.GetInternalAsync();
ObjectsApi objects = new ObjectsApi();
objects.Configuration.AccessToken = oauth.access_token;
// upload the file/object, which will create a new object
dynamic uploadedObj;
using (StreamReader streamReader = new StreamReader(fileSavePath))
{
uploadedObj = await objects.UploadObjectAsync(bucketKey,file.FileName,
(int)streamReader.BaseStream.Length, streamReader.BaseStream,"application/octet-
stream");
}
// cleanup
File.Delete(fileSavePath);
return uploadedObj;
}
I am using ui-router with Angular and Node.js as my UI server for API calls to another server. Right now, my browser URL (dynamic based on dropdown selections) does not map to the server.
For example, the browser URL is "/home?color=Red&&size=Large" when I send the user inputs to Node. When I copy and paste that URL in another browser window, I want the color and size dropdowns to already be selected as Red and Large, and results from API call based on the selections displayed. How can I accomplish this?
My AngularJS controller code:
$scope.getResults = function() {
$location.search('color', $scope.myColor);
$location.search('size', $scope.mySize);
server.getResults($scope.myColor, $scope.mySize)
.success(function(data) {
results = data;
});
};
AngularJS service for the above function:
app.factory('server', ['$http', function($http){
return {
getResults : function(color, size) {
var req = {};
req.color = color;
req.size = size;
return $http({
method: 'GET',
url: 'results',
params : req
});
}
}
}]);
ui-router in Angular:
$stateProvider.state('home', {
url: '/home',
templateUrl: '/home.html',
controller: 'MainCtrl',
reloadOnSearch: false
})
In Node.js, I have my route like this:
app.get("/results", function (req, res) {
var api = 'some api call/' + req.query.color + '/' + req.query.size;
request(api, function (error, response, api) {
if (!error && response.statusCode == 200) {
res.json({
Response: api
});
}
});
});
In your code you wrote query parameters but you need to read them, try this:
$scope.getResults = function() {
$scope.myColor = $location.search().color;
$scope.mySize = $location.search().size;
server.getResults($scope.myColor, $scope.mySize)
.success(function(data) {
results = data;
});
};
The situation that I am specifically referring to involves the use of json web tokens (jwt). For example how would I automatically add middleware to only return a new json web token if that web token is expired without duplicating code? The sample code below will show what I mean.
var express = require("express");
var jwt = require('jsonwebtoken');
var router = express.Router();
router.use(function(req,res,next){
var token = req.body.token || req.query.token;
if (token) {
jwt.verify(token,"secretTingz",{algorithms:["RS256"]},function(err,decoded){
if (err) {
if (token.expired) {
// HOW DO I GET THIS PIECE OF CODE TO RUN FOR EVERY VALID ROUTE THAT NEEDS A NEW TOKEN WITHOUT DUPLICATING CODE?
var token = jwt.sign({user:"MilnerJenkins"},cert,{algorithm:"RS256",expiresInMinutes:1});
req.token = token;
next();
}else{
return res.json({message:"Failed to authenticate token"});
}
}else{
req.decoded = decoded;
next();
}
})
}else{
return res.status(403).send({
message: "No token!"
});
}
});
apiRoutes.get("/stuff",function(req,res){
var token;
if (req.token) {
token = req.token;
};
res.json({message: "Dope API son!",token:token});
});
apiRoutes.get("/users",function(req,res){
var token;
if (req.token) {
token = req.token;
};
User.find({},function(err,users){
res.json({users: users, token: token});
});
});
As you can see code is being duplicated in both routes with this block:
var token;
if (req.token) {
token = req.token;
};
What can I do with express middleware to prevent this duplication?
The only way you could do this with a "middleware" is by having a handler at the end of your middlware chain that would send the response. That would mean all your handlers would have to pass the request and response down the chain. It would essentially be the last handler before your 404 handler. I do not recommend attempting that. Alternatively you can create a custom response method for your express app.
var app = require('express')();
app.response.myJsonRes = function(obj) {
if (this.req.token) {
obj.token = this.req.token;
}
this.json(obj);
};
app.get('/myRoute', function(req, res) {
// get data somehow
res.myJsonRes(data);
});
You coulld even change the standard json method.
var prevJson = app.response.json;
app.response.json = function(obj) {
if (this.req.token) {
obj.token = this.req.token;
}
prevJson.call(this, obj);
};
I am trying to use a Json request to get data from a login screen. But no matter if the login request is valid or not, I am always getting returned to my home screen. I think I am checking the result incorrectly?
Basically, in my Twitter-Bootstrap enabled site, I have a modal popup that takes the user to a login form.
The values are passed via a json query, to my MVC4 controller. A breakpoint shows I am getting good data.
Here's the scrip that sends the data:
<script type="text/javascript">
$(document).ready(function () {
$('.btnSubmit').on('click', function () {
var data = { username: $('.txtUsername').val(), password: $('.txtPassword').val(), rememberMe: $('.cbRemember').val() };
$.ajax({
url: '#Url.Action("LoginUser", "User")',
type: "POST",
contentType: "application/json",
data: JSON.stringify(data),
cache: false,
async: true,
success: function (result) {
if (result['success'] == 'true') {
alert("true");
window.location = '#Url.Action("Index", "Home")';
} else {
alert("BAD");
}
},
error: function () {
alert("Error in input");
}
});
});
});
</script>
And here is the controller method:
[HttpPost]
public JsonResult LoginUser(string username, string password, string rememberMe)
{
string success = "false";
string message = "Not set";
if (username == string.Empty || password == string.Empty)
{
success = "false";
message = "Invalid Username/Password";
}
else
{
if (ModelState.IsValid)
{
var us = new UserService();
var reply = us.Authenticate(username, Security.EncryptText(password));
if (reply == 0)
{
success = "false";
message = "Invalid Username/Password";
}
if (reply != 0)
{
var p = us.GetPerson(reply);
FormsAuthentication.SetAuthCookie(p.Id.ToString(CultureInfo.InvariantCulture), rememberMe == "on");
Session["UserDisplay"] = string.Format("{0} {1} - ({2})", p.Firstname, p.Surname, p.Email);
success = "true";
message = "Login Success";
}
}
}
var result = new { Success = success, Message = message };
var r = new JsonResult
{
Data = result
};
return r;
}
However, I always get the 'BAD' alert. Never the 'true'.
Can I check the result the way I am? Am I attempting to do this the right way? Basically, if I get 'BAD', I don't want the screen to refresh. Infact, I will want to show a message saying what ever is in the 'message' parameter.
Edit: I think 'result' is NULL.