In previous versions of angularFire, it was possible to secure selected routes by using "authRequired" and "pathTo" with Angular's $routeProvider. These no longer appear to work with AngularFire 0.6.0. What is the equivalent parameter/technique in Angular 0.6.0?
Routing was moved out of angularFire for the same reasons it was moved out of the core of Angular--to be less opinionated in how routing is conducted and which lib you should use.
You can still include routing by grabbing the module from angularFire-seed, which is plug-and-play ready.
The steps are:
add ngRoute and routeSecurity to your app dependencies
declare the loginRedirectPath constant
add authRequired where appropriate
Example:
// add routeSecurity to your dependency libs
angular.module('myApp', [..., 'ngRoute', 'firebase', 'routeSecurity']);
// declare the loginRedirectPath variable
angular.module('myApp').constant('loginRedirectPath', '/login')
// put authRequired in your routes
$routeProvider.when('/account', {
authRequired: true, // must authenticate before viewing this page
templateUrl: 'partials/account.html',
controller: 'AccountCtrl'
});
// live long and prosper
Here's a hard copy of the module as of 0.6.0 for compliance with SO policy; refer directly to the source for a current version:
(function(angular) {
angular.module('routeSecurity', [])
.run(['$injector', '$location', '$rootScope', 'loginRedirectPath', function($injector, $location, $rootScope, loginRedirectPath) {
if( $injector.has('$route') ) {
new RouteSecurityManager($location, $rootScope, $injector.get('$route'), loginRedirectPath);
}
}]);
function RouteSecurityManager($location, $rootScope, $route, path) {
this._route = $route;
this._location = $location;
this._rootScope = $rootScope;
this._loginPath = path;
this._redirectTo = null;
this._authenticated = !!($rootScope.auth && $rootScope.auth.user);
this._init();
}
RouteSecurityManager.prototype = {
_init: function() {
var self = this;
this._checkCurrent();
// Set up a handler for all future route changes, so we can check
// if authentication is required.
self._rootScope.$on("$routeChangeStart", function(e, next) {
self._authRequiredRedirect(next, self._loginPath);
});
self._rootScope.$on('$firebaseSimpleLogin:login', angular.bind(this, this._login));
self._rootScope.$on('$firebaseSimpleLogin:logout', angular.bind(this, this._logout));
self._rootScope.$on('$firebaseSimpleLogin:error', angular.bind(this, this._error));
},
_checkCurrent: function() {
// Check if the current page requires authentication.
if (this._route.current) {
this._authRequiredRedirect(this._route.current, this._loginPath);
}
},
_login: function() {
this._authenticated = true;
if( this._redirectTo ) {
this._redirect(this._redirectTo);
this._redirectTo = null;
}
else if( this._location.path() === this._loginPath ) {
this._location.replace();
this._location.path('/');
}
},
_logout: function() {
this._authenticated = false;
this._checkCurrent();
},
_error: function() {
if( !this._rootScope.auth || !this._rootScope.auth.user ) {
this._authenticated = false;
}
this._checkCurrent();
},
_redirect: function(path) {
this._location.replace();
this._location.path(path);
},
// A function to check whether the current path requires authentication,
// and if so, whether a redirect to a login page is needed.
_authRequiredRedirect: function(route, path) {
if (route.authRequired && !this._authenticated){
if (route.pathTo === undefined) {
this._redirectTo = this._location.path();
} else {
this._redirectTo = route.pathTo === path ? "/" : route.pathTo;
}
this._redirect(path);
}
else if( this._authenticated && this._location.path() === this._loginPath ) {
this._redirect('/');
}
}
};
})(angular);
Related
I have alfresco share/repo version 5.2.3
I'm trying to modifiy the function found in _AlfDndDocumentUploadMixin.js with the fix that has been posted on https://github.com/Alfresco/Aikau/blob/1.0.101_hotfixes/aikau/src/main/resources/alfresco/documentlibrary/_AlfDndDocumentUploadMixin.js
I tried extending the attachment-doclib.xml and get the jsonmodul, but it gives me a null pointer.
My code is the following
From attachment-doclib.get.js
var documentServices = model.jsonModel;
for (var i=0; i<documentServices.length; i++)
{
if (documentServices[i] === "alfresco/documentlibrary")
{
documentServices[i] = "js/aikau/1.0.101.10/alfresco/documentlibrary/my-documentlibrary/_AlfDndDocumentUploadMixin-extension";
}
else if (documentServices[i].name === "alfresco/documentlibrary")
{
documentServices[i].name = "js/aikau/1.0.101.10/alfresco/documentlibrary/my-documentlibrary/_AlfDndDocumentUploadMixin-extension";
}
}
from doclib-customizations.xml
<config evaluator="string-compare" condition="WebFramework" replace="false">
<web-framework>
<dojo-pages>
<packages>
<package name="documentlibrary" location="js/aikau/1.0.101.10/alfresco/documentlibrary" />
</packages>
</dojo-pages>
</web-framework>
</config>
From _alfDndDocumentUploadMixin-extended.js
onDndUploadDrop: function alfresco_documentlibrary__AlfDndDocumentUploadMixin__onDndUploadDrop(evt) {
try
{
// Only perform a file upload if the user has *actually* dropped some files!
this.alfLog("log", "Upload drop detected", evt);
if (evt.dataTransfer.files !== undefined && evt.dataTransfer.files !== null && evt.dataTransfer.files.length > 0)
{
this.removeDndHighlight();
var destination = this._currentNode ? this._currentNode.nodeRef : null;
var config = this.getUploadConfig();
var defaultConfig = {
destination: destination,
siteId: null,
containerId: null,
uploadDirectory: null,
updateNodeRef: null,
description: "",
overwrite: false,
thumbnails: "doclib",
username: null
};
var updatedConfig = lang.mixin(defaultConfig, config);
var walkFileSystem = lang.hitch(this, function alfresco_documentlibrary__AlfDndDocumentUploadMixin__onDndUploadDrop__walkFileSystem(directory, callback, error) {
callback.limit = this.dndMaxFileLimit;
callback.pending = callback.pending || 0;
callback.files = callback.files || [];
// get a dir reader and cleanup file path
var reader = directory.createReader(),
relativePath = directory.fullPath.replace(/^\//, "");
var repeatReader = function alfresco_documentlibrary__AlfDndDocumentUploadMixin__onDndUploadDrop__walkFileSystem__repeatReader() {
// about to start an async callback function
callback.pending++;
reader.readEntries(function alfresco_documentlibrary__AlfDndDocumentUploadMixin__onDndUploadDrop__walkFileSystem__repeatReader__readEntries(entries) {
// processing an async callback function
callback.pending--;
array.forEach(entries, function(entry) {
if (entry.isFile)
{
// about to start an async callback function
callback.pending++;
entry.file(function(File) {
// add the relativePath property to each file - this can be used to rebuild the contents of
// a nested tree folder structure if an appropriate API is available to do so
File.relativePath = relativePath;
callback.files.push(File);
if (callback.limit && callback.files.length > callback.limit)
{
throw new Error("Maximum dnd file limit reached: " + callback.limit);
}
// processing an async callback function
if (--callback.pending === 0)
{
// fall out here if last item processed is a file entry
callback(callback.files);
}
}, error);
}
else
{
walkFileSystem(entry, callback, error);
}
});
// the reader API is a little esoteric,from the MDN docs:
// "Continue calling readEntries() until an empty array is returned.
// You have to do this because the API might not return all entries in a single call."
if (entries.length !== 0)
{
repeatReader();
}
// fall out here if last item processed is a dir entry e.g. empty dir
if (callback.pending === 0)
{
callback(callback.files);
}
}, error);
};
repeatReader();
});
var addSelectedFiles = lang.hitch(this, function alfresco_documentlibrary__AlfDndDocumentUploadMixin__onDndUploadDrop__addSelectedFiles(files) {
if (this.dndMaxFileLimit && files.length > this.dndMaxFileLimit)
{
throw new Error("Maximum dnd file limit reached: " + this.dndMaxFileLimit);
}
// Check to see whether or not the generated upload configuration indicates
// that an existing node will be created or not. If node is being updated then
// we need to generate an intermediary step to capture version and comments...
if (updatedConfig.overwrite === false)
{
// Set up a response topic for receiving notifications that the upload has completed...
var responseTopic = this.generateUuid();
this._uploadSubHandle = this.alfSubscribe(responseTopic, lang.hitch(this, this.onFileUploadComplete), true);
this.alfPublish(topics.UPLOAD_REQUEST, {
alfResponseTopic: responseTopic,
files: files,
targetData: updatedConfig
}, true);
}
else
{
// TODO: Check that only one file has been dropped and issue error...
this.publishUpdateRequest(updatedConfig, files);
}
});
var items = evt.dataTransfer.items || [], firstEntry;
// webkitGetAsEntry is a marker for determining FileSystem API support.
// SHA-2164 - Firefox claims support, but different impl. rather than code around differences, fallback.
if (items[0] && items[0].webkitGetAsEntry && !has("ff") && (firstEntry = items[0].webkitGetAsEntry()))
{
walkFileSystem(firstEntry.filesystem.root, function(files) {
addSelectedFiles(files);
}, function() {
// fallback to standard way if error happens
addSelectedFiles(evt.dataTransfer.files);
}
);
}
else
{
// fallback to standard way if no support for filesystem API
addSelectedFiles(evt.dataTransfer.files);
}
}
else
{
this.alfLog("error", "A drop event was detected, but no files were present for upload: ", evt.dataTransfer);
}
}
catch(exception)
{
this.alfLog("error", "The following error occurred when files were dropped onto the Document List: ", exception);
}
// Remove the drag highlight...
this.removeDndHighlight();
// Destroy the overlay node (required for views that will re-render all the contents)...
domConstruct.destroy(this.dragAndDropOverlayNode);
this.dragAndDropOverlayNode = null;
evt.stopPropagation();
evt.preventDefault();
},
/**
* This function publishes an update version request. It will request that a new dialog
* be displayed containing the form controls defined in
* [widgetsForUpdate]{#link module:alfresco/documentlibrary/_AlfDndDocumentUploadMixin#widgetsForUpdate}.
*
* #instance
* #param {object} uploadConfig
*
* #fires ALF_CREATE_FORM_DIALOG_REQUEST
*/
publishUpdateRequest: function alfresco_documentlibrary__AlfDndDocumentUploadMixin__publishUpdateRequest(uploadConfig, files) {
// TODO: Work out the next minor and major increment versions...
// TODO: Localization required...
// Set up a response topic for receiving notifications that the upload has completed...
var responseTopic = this.generateUuid();
this._uploadSubHandle = this.alfSubscribe(responseTopic, lang.hitch(this, this.onFileUploadComplete), true);
// To avoid the issue with processing payloads containing files with native
// code in them, it is necessary to temporarily store the files in the data model...
var filesRef = this.generateUuid();
this.alfSetData(filesRef, files);
this.alfPublish("ALF_CREATE_FORM_DIALOG_REQUEST", {
dialogTitle: "Update",
dialogConfirmationButtonTitle: "Continue Update",
dialogCancellationButtonTitle: "Cancel",
formSubmissionTopic: topics.UPLOAD_REQUEST,
formSubmissionPayloadMixin: {
alfResponseTopic: responseTopic,
filesRefs: filesRef,
targetData: uploadConfig
},
fixedWidth: true,
widgets: lang.clone(this.widgetsForUpdate)
}, true);
},
Expect: All files that are dragged and drop to be uploaded.
Actual: Only one file is uploaded
(function ($) {
var webcam = {
"extern": null, // external select token to support jQuery dialogs
"append": true, // append object instead of overwriting
"width": 320,
"height": 240,
"mode": "callback", // callback | save | stream
"swffile": "../Webcam_Plugin/jscam_canvas_only.swf",
"quality": 85,
"debug": function () {},
"onCapture": function () {},
"onTick": function () {},
"onSave": function () {},
"onLoad": function () {}
};
window["webcam"] = webcam;
$["fn"]["webcam"] = function(options) {
if (typeof options === "object") {
for (var ndx in webcam) {
if (options[ndx] !== undefined) {
webcam[ndx] = options[ndx];
}
}
}
var source = '<object id="XwebcamXobjectX" type="application/x-shockwave-flash" data="'+webcam["swffile"]+'" width="'+webcam["width"]+'" height="'+webcam["height"]+'"><param name="movie" value="'+webcam["swffile"]+'" /><param name="FlashVars" value="mode='+webcam["mode"]+'&quality='+webcam["quality"]+'" /><param name="allowScriptAccess" value="always" /></object>';
if (null !== webcam["extern"]) {
$(webcam["extern"])[webcam["append"] ? "append" : "html"](source);
} else {
this[webcam["append"] ? "append" : "html"](source);
}
var run = 3;
(_register = function() {
var cam = document.getElementById('XwebcamXobjectX');
if (cam && cam["capture"] !== undefined) {
/* Simple callback methods are not allowed :-/ */
webcam["capture"] = function(x) {
try {
return cam["capture"](x);
} catch(e) {}
}
webcam["save"] = function(x) {
try {
return cam["save"](x);
} catch(e) {}
}
webcam["setCamera"] = function(x) {
try {
return cam["setCamera"](x);
} catch(e) {}
}
webcam["getCameraList"] = function() {
try {
return cam["getCameraList"]();
} catch(e) {}
}
webcam["pauseCamera"] = function() {
try {
return cam["pauseCamera"]();
} catch(e) {}
}
webcam["resumeCamera"] = function() {
try {
return cam["resumeCamera"]();
} catch(e) {}
}
webcam["onLoad"]();
} else if (0 == run) {
webcam["debug"]("error", "Flash movie not yet registered!");
} else {
/* Flash interface not ready yet */
run--;
window.setTimeout(_register, 1000 * (4 - run));
}
})();
}
})(jQuery);
Above is the function which I've used in order to access the webcam of the system. It work fine when i use it on localhost but the problem arises when the same is put on the server and then accessed through intranet.
I'm unable to find the reason to fix it. Kindly help me with the same.
The first two images are the ones when i use my code on localhost. It works fine as i'm able to access the webcam.
Problem statement:
The last image is the one where I try to do the same through server. The webcam opens by the images is completely wiped out. Only a white screen appears and even if I capture the photo through webcam, the white image is only saved on server instead of a proper original image.
Because of security reasons you have to serve the Site over Https to access the camera.
Yesterday my app was launched, Ionic v1, and a few users entered the wrong password and can't log into the app.
The app uses firebase authentication. I have a __refs file that points to the database and have tried numerous things trying to get the reset to work.
I've tried referencing $firebaseAuth, of course my __refs, $firebase then use $firebase.auth()...
I didn't write the authentication of this app so I'm not real sure how it works. I'm hoping that someone can help me.
My reset controller
angular.module('formulaWizard').controller('ResetPasswordCtrl',
function($scope, $ionicLoading, $firebaseAuth, __Refs) {
$scope.user = {
email: ''
};
$scope.errorMessage = null;
var fbAuth = $firebaseAuth(__Refs.rootRef);
$scope.resetPassword = function() {
$scope.errorMessage = null;
$ionicLoading.show({
template: 'Please wait...'
});
fbAuth.sendPasswordResetEmail($scope.user.email)
.then(showConfirmation)
.catch(handleError);
};
function showConfirmation() {
$scope.emailSent = true;
$ionicLoading.hide();
}
function handleError(error) {
switch (error.code) {
case 'INVALID_EMAIL':
case 'INVALID_USER':
$scope.errorMessage = 'Invalid email';
break;
default:
$scope.errorMessage = 'Error: [' + error.code + ']';
}
$ionicLoading.hide();
}
});
My Refs file
angular.module('formulaWizard')
.factory('__Refs', function ($firebaseArray, $firebaseObject) {
// Might use a resource here that returns a JSON arrayf
var ref = new Firebase('https://firebasedatabase.com/');
return {
rootRef: ref,
customers: ref.child('customers'),
}
});
I can't take credit for the answer it was provide by Abimbola Idowu on HackHands.
Since I paid for the answer I thought I would share it with anyone else that might also be stumped by this.
$scope.resetPassword = function() {
$scope.errorMessage = null;
$ionicLoading.show({
template: 'Please wait...'
});
__Refs.rootRef.resetPassword({ email: $scope.user.email }, function(error) {
if (error === null) {
showConfirmation();
} else {
handleError()
}
});
};
This is the __refs service
angular.module('formulaWizard')
.factory('__Refs', function ($firebaseArray, $firebaseObject) {
// Might use a resource here that returns a JSON arrayf
var ref = new Firebase('https://firebasedatabase.com/');
return {
rootRef: ref,
}
});
I've been trying to use bokeh server to get interactive plots served over an https website. I use an autoload_server generated script to pull plots from the server. However, I've run into problems wherein the autoload.js file obtained from the bokeh server injects http versions of the css/js files into the script.
Is there any way to avoid having bokeh serve http content in order to avoid content mixing errors? Even better, is it possible to configure bokeh to serve content over https?
Thanks!
(function(global) {
function now() {
return new Date();
}
if (typeof (window._bokeh_onload_callbacks) === "undefined") {
window._bokeh_onload_callbacks = [];
}
function run_callbacks() {
window._bokeh_onload_callbacks.forEach(function(callback) { callback() });
delete window._bokeh_onload_callbacks
console.info("Bokeh: all callbacks have finished");
}
function load_libs(js_urls, callback) {
window._bokeh_onload_callbacks.push(callback);
if (window._bokeh_is_loading > 0) {
console.log("Bokeh: BokehJS is being loaded, scheduling callback at", now());
return null;
}
if (js_urls == null || js_urls.length === 0) {
run_callbacks();
return null;
}
console.log("Bokeh: BokehJS not loaded, scheduling load and callback at", now());
window._bokeh_is_loading = js_urls.length;
for (var i = 0; i < js_urls.length; i++) {
var url = js_urls[i];
var s = document.createElement('script');
s.src = url;
s.async = false;
s.onreadystatechange = s.onload = function() {
window._bokeh_is_loading--;
if (window._bokeh_is_loading === 0) {
console.log("Bokeh: all BokehJS libraries loaded");
run_callbacks()
}
};
s.onerror = function() {
console.warn("failed to load library " + url);
};
console.log("Bokeh: injecting script tag for BokehJS library: ", url);
document.getElementsByTagName("head")[0].appendChild(s);
}
};var element = document.getElementById("976c2ae5-68de-4787-815c-852a1de3e3b0");
if (element == null) {
console.log("Bokeh: ERROR: autoload.js configured with elementid '976c2ae5-68de-4787-815c-852a1de3e3b0' but no matching script tag was found. ")
return false;
}var js_urls = ['http://website.com/static/js/bokeh.min.js?v=b0e2720e424bae5562ceecc6d83c2044', 'http://website.com/static/js/bokeh-widgets.min.js?v=8e88133dddc48883a815d4278dd80f9a', 'http://website.com/static/js/bokeh-compiler.min.js?v=34cb81b761c2c28f1955c7bb98dab3a9'];
var inline_js = [
function(Bokeh) {
Bokeh.set_log_level("info");
},
function(Bokeh) {
Bokeh.$(function() {
var docs_json = null;
var render_items = [{"sessionid": "nZqXOULM3zcQBaz1GDCOTLVIoa4a0UrlJIMzGCMzCTZk", "elementid": "976c2ae5-68de-4787-815c-852a1de3e3b0", "use_for_title": true}];
Bokeh.embed.embed_items(docs_json, render_items, "ws://website.com/ws");
});
},
function(Bokeh) {
console.log("Bokeh: injecting CSS: http://website.com/static/css/bokeh.min.css?v=486d3195473d3e39ad36f2888fefe389");
Bokeh.embed.inject_css("http://website.com/static/css/bokeh.min.css?v=486d3195473d3e39ad36f2888fefe389");
console.log("Bokeh: injecting CSS: http://website.com/static/css/bokeh-widgets.min.css?v=0bbd11cf0fab2f648f3918c073bc9c3d");
Bokeh.embed.inject_css("http://website.com/static/css/bokeh-widgets.min.css?v=0bbd11cf0fab2f648f3918c073bc9c3d");
}
];
function run_inline_js() {
for (var i = 0; i < inline_js.length; i++) {
inline_js[i](window.Bokeh);
}
}
if (window._bokeh_is_loading === 0) {
console.log("Bokeh: BokehJS loaded, going straight to plotting");
run_inline_js();
} else {
load_libs(js_urls, function() {
console.log("Bokeh: BokehJS plotting callback run at", now());
run_inline_js();
});
}
}(this));
I am using keystone#0.2.32. I would like to change the post category to a tree structure. The below code is running well except when I create a category, it goes into a deadlock:
var keystone = require('keystone'),
Types = keystone.Field.Types;
/**
* PostCategory Model
* ==================
*/
var PostCategory = new keystone.List('PostCategory', {
autokey: { from: 'name', path: 'key', unique: true }
});
PostCategory.add({
name: { type: String, required: true },
parent: { type: Types.Relationship, ref: 'PostCategory' },
parentTree: { type: Types.Relationship, ref: 'PostCategory', many: true }
});
PostCategory.relationship({ ref: 'Post', path: 'categories' });
PostCategory.scanTree = function(item, obj, done) {
if(item.parent){
PostCategory.model.find().where('_id', item.parent).exec(function(err, cats) {
if(cats.length){
obj.parentTree.push(cats[0]);
PostCategory.scanTree(cats[0], obj, done);
}
});
}else{
done();
}
}
PostCategory.schema.pre('save', true, function (next, done) { //Parallel middleware, waiting done to be call
if (this.isModified('parent')) {
this.parentTree = [];
if(this.parent != null){
this.parentTree.push(this.parent);
PostCategory.scanTree(this, this, done);
}else
process.nextTick(done);
}else
process.nextTick(done); //here is deadlock.
next();
});
PostCategory.defaultColumns = 'name, parentTree';
PostCategory.register();
Thanks so much.
As I explained on the issue you logged on Keystone here: https://github.com/keystonejs/keystone/issues/759
This appears to be a reproducible bug in mongoose that prevents middleware from resolving when:
Parallel middleware runs that executes a query, followed by
Serial middleware runs that executes a query
Changing Keystone's autokey middleware to run in parallel mode may cause bugs in other use cases, so cannot be done. The answer is to implement your parentTree middleware in serial mode instead of parallel mode.
Also, some other things I noticed:
There is a bug in your middleware, where the first parent is added to the array twice.
The scanTree method would be better implemented as a method on the schama
You can use the findById method for a simpler parent query
The schema method looks like this:
PostCategory.schema.methods.addParents = function(target, done) {
if (this.parent) {
PostCategory.model.findById(this.parent, function(err, parent) {
if (parent) {
target.parentTree.push(parent.id);
parent.addParents(target, done);
}
});
} else {
done();
}
}
And the fixed middleware looks like this:
PostCategory.schema.pre('save', function(done) {
if (this.isModified('parent')) {
this.parentTree = [];
if (this.parent != null) {
PostCategory.scanTree(this, this, done);
} else {
process.nextTick(done);
}
} else {
process.nextTick(done);
}
});
I think it's a bug of keystone.js. I have changed schemaPlugins.js 104 line
from
this.schema.pre('save', function(next) {
to
this.schema.pre('save', true, function(next, done) {
and change from line 124 to the following,
// if has a value and is unmodified or fixed, don't update it
if ((!modified || autokey.fixed) && this.get(autokey.path)) {
process.nextTick(done);
return next();
}
var newKey = utils.slug(values.join(' ')) || this.id;
if (autokey.unique) {
r = getUniqueKey(this, newKey, done);
next();
return r;
} else {
this.set(autokey.path, newKey);
process.nextTick(done);
return next();
}
It works.