<commit_before>/*live version*/
var ajaxThemeList = {
  init: function(settings) {
    ajaxThemeList.settings = {
      $listContainer: jQuery('#ajaxtheme_list'),
      pageClass: 'ajaxtheme_page',
      sortClass: 'ajaxtheme_sort',
      $formBatch: jQuery('#sf_admin_content form'),
      $filterContainer: jQuery('#sf_admin_bar'),
      resetClass: 'ajaxtheme_reset',
      baseURL: location.protocol + '//' + location.host + location.pathname
    };
    jQuery.extend(ajaxThemeList.settings, settings);
    ajaxThemeList.onReady();

    /*taken from https://gist.github.com/raw/358429*/
    jQuery(window).bind( 'hashchange', function(e) {
      var settings = ajaxThemeList.settings;
      var params = e.fragment;
      if (params) getHTMLAjaxResponse('GET', jQuery.param.querystring(settings.baseURL, params), {}, settings.$listContainer, settings.$filterContainer);
    });

    if (window.location.hash) jQuery(window).trigger('hashchange');

  },
  onReady : function() {
    ajaxThemeList.livePaginationAndSorting();
    ajaxThemeList.liveBatchAction();
    ajaxThemeList.liveFormFilter();
  },

  livePaginationAndSorting: function () {
    var settings = ajaxThemeList.settings;
    settings.$listContainer.find("a[class="+settings.pageClass+"], a[class="+settings.sortClass+"]").live('click', function(e) {
      var params = jQuery.deparam.querystring(this.href);
      var new_url = jQuery.param.fragment(settings.baseURL, params, 2);
      window.location.hash = jQuery.param.fragment( new_url );
      return false;
    });
  },
  liveBatchAction: function() {
    var formBatch = ajaxThemeList.settings.$formBatch;
    if (formBatch.length > 0) {
      formBatch.find('input[type=submit]').live('click', function(e) {
        return getJSONAjaxResponse('POST', formBatch.attr('action'), formBatch.serialize(), ajaxThemeList.settings.$listContainer);
      });
    }
  },
  liveFormFilter: function() {
    var settings = ajaxThemeList.settings;
    if (settings.$filterContainer.length > 0) {
      var formFilter = settings.$filterContainer.find('form');
      formFilter.find('input[type=submit]').live('click', function(e) {
        e.preventDefault(); //should be here, to enable event delegation
        window.location.hash = '#';
        return getHTMLAjaxResponse('POST', formFilter.attr('action'), formFilter.serialize(), settings.$listContainer);
      });
      formFilter.find('a[class='+settings.resetClass+']').live('click', function(e) {
        e.preventDefault();
        window.location.hash = '#';
        return getHTMLAjaxResponse('GET', this.href, {}, settings.$listContainer, settings.$filterContainer);
      });
    }
  }
};

jQuery(document).ready(function() {
  ajaxThemeList.init();
  showIndicator();
});<commit_msg>[ajaxTheme-listl.js] bug-fix submit filter<commit_after>/*live version*/
var ajaxThemeList = {
  init: function(settings) {
    ajaxThemeList.settings = {
      $listContainer: jQuery('#ajaxtheme_list'),
      pageClass: 'ajaxtheme_page',
      sortClass: 'ajaxtheme_sort',
      $formBatch: jQuery('#sf_admin_content form'),
      $filterContainer: jQuery('#sf_admin_bar'),
      resetClass: 'ajaxtheme_reset',
      baseURL: location.protocol + '//' + location.host + location.pathname
    };
    jQuery.extend(ajaxThemeList.settings, settings);
    ajaxThemeList.onReady();

    /*taken from https://gist.github.com/raw/358429*/
    jQuery(window).bind( 'hashchange', function(e) {
      var settings = ajaxThemeList.settings;
      var params = e.fragment;
      if (params) getHTMLAjaxResponse('GET', jQuery.param.querystring(settings.baseURL, params), {}, settings.$listContainer, settings.$filterContainer);
    });

    if (window.location.hash) jQuery(window).trigger('hashchange');

  },
  onReady : function() {
    ajaxThemeList.livePaginationAndSorting();
    ajaxThemeList.liveBatchAction();
    ajaxThemeList.liveFormFilter();
  },

  livePaginationAndSorting: function () {
    var settings = ajaxThemeList.settings;
    settings.$listContainer.find("a[class="+settings.pageClass+"], a[class="+settings.sortClass+"]").live('click', function(e) {
      var params = jQuery.deparam.querystring(this.href);
      var new_url = jQuery.param.fragment(settings.baseURL, params, 2);
      window.location.hash = jQuery.param.fragment( new_url );
      return false;
    });
  },
  liveBatchAction: function() {
    var formBatch = ajaxThemeList.settings.$formBatch;
    if (formBatch.length > 0) {
      formBatch.find('input[type=submit]').live('click', function(e) {
        return getJSONAjaxResponse('POST', formBatch.attr('action'), formBatch.serialize(), ajaxThemeList.settings.$listContainer);
      });
    }
  },
  liveFormFilter: function() {
    var settings = ajaxThemeList.settings;
    if (settings.$filterContainer.length > 0) {
      settings.$filterContainer.find('input[type=submit]').live('click', function(e) {
        e.preventDefault();
        window.location.hash = '#';
        return getHTMLAjaxResponse('POST', settings.$filterContainer.find('form').attr('action'), settings.$filterContainer.find('form').serialize(), settings.$listContainer);
      });
      settings.$filterContainer.find('a[class='+settings.resetClass+']').live('click', function(e) {
        e.preventDefault();
        window.location.hash = '#';
        return getHTMLAjaxResponse('GET', this.href, {}, settings.$listContainer, settings.$filterContainer);
      });
    }
  }
};

jQuery(document).ready(function() {
  ajaxThemeList.init();
  showIndicator();
});
<|endoftext|>


<commit_before>"use strict";

var url = require("url");
var Types = require("./types").Types;
var Route = require("./route");
var flatten = require("./utils").flatten;

module.exports = function Section(name, description, types) {

    types = types || new Types();
    var routes = [];
    var sections = {};
    var self = this;

    this.middlewares = [];
    this.globals = [];
    this.errorHandlers = [];
    this.name = name;

    var methods = ["head", "get", "put", "post", "delete", "patch", "upgrade", "options"];
    methods.forEach(function(method) {
        routes[method] = [];

        self[method] = (function(method, route, options, handler) {
            // options is optional
            if (typeof options == "function" || Array.isArray(options)) {
                handler = options;
                options = {};
            }
            options.method = method;
            return self._route(route, options, handler);
        }).bind(self, method);
    });
    this.del = this["delete"];

    this.registerType = types.register.bind(types);

    this.all = function(method, route, options, handler) {
        var self = this;
        var args = arguments;

        methods.forEach(function(method) {
            self[method].apply(self, args);
        });
    };

    /**
     * Insert global middleware(s) for this section: The parent section is
     * always an empty container that delegates to it's sub-sections, and
     * executes all the middelwares for that section.
     *
     * This method allows us to inject a "global" middleware that is inserted
     * *after* decodeParams and *before* all other middelwares.
     */
    this.global = function( middleware ){
        this.globals.push.apply(this.globals, flatten(middleware));
    };

    this.use = function(middleware) {
        this.middlewares.push.apply(this.middlewares, flatten(middleware));
    };

    this.error = function(middleware) {
        this.errorHandlers.push.apply(this.errorHandlers, flatten(middleware));
    };

    this._route = function(route, options, handler) {
        route = new Route(route, options, handler, types);
        route.parent = this;
        routes[route.method].push(route);
        return this;
    };

    this.section = function(name, description) {
        var section = new Section(name, description, types);
        section.parent = this;
        if (!sections[name])
            sections[name] = [];

        sections[name].push(section);
        return section;
    };

    this.getRoutes = function(){
        return routes;
    };

    /**
     * Mount an existing section on this instance.
     *
     * Note that when the first argument is omitted, the section's routes will
     * be copied onto this instance's routing table.
     *
     * @param {string} mountpoint Where to mount this secion, e.g. "/capture/"
     * @param {Section} section A frontdoor section
     */

    this.mount = function(name, section) {
        if ( arguments.length == 1 ){
            section = arguments[0];

            if ( ! ( section instanceof Section ) )
                throw new Error("Single argument to mount must be a Section!");

            var addRoutes = section.getRoutes();

            Object.keys(addRoutes).forEach(function(  method){
                routes[method] = [].concat( routes[method], addRoutes[method] );
            });

            return;
        }

        if (!sections[name])
            sections[name] = [];

        section.parent = this;
        sections[name].push(section);
    };

    /**
     * Sortcut for client-side routing without a `next`
     *
     * Allows you to omit the third argument, "next" and avoid special
     * treatment in router.js (see "wrapHandler").
     *
     * Has a variable number of argumnets: no need to wrap handlers in an array
     */
    this.on = function( path, handler ){
        var middlewares = Array.prototype.slice.call( arguments, 1 );
        handler = middlewares.shift();

        middlewares.unshift(function(req, res, next){
            handler( req, res, next );
        });

        this._route( path, { method: "get" }, middlewares );
    };

    this._rootHandler = function(req, res) {
        this.handle(req, res, function(err) {
            if (err) {
                res.statusCode = err.code || err.statusCode || 500;
                res.end(err.message || err.toString);
            } else {
                res.statusCode = 404;
                res.end("cannot " + req.method);
            }
        });
    };

    this.handle = (function(path, req, res, next) {
        var that = this;

        if (arguments.length == 2) {
            return this._rootHandler.apply(this, arguments);
        }

        if (arguments.length === 3) {
            req = arguments[0];
            res = arguments[1];
            next = arguments[2];

            if (!req.parsedUrl)
                req.parsedUrl = url.parse(req.url, true);

            path = req.parsedUrl.pathname;
        }

        req.params = req.params || {};

        var method = req.method.toLowerCase();
        if (methods.indexOf(method) == -1)
            return next();

        var handler = this.match(req, path, method);
        if (!handler)
            return next();

        var middleware = [];
        var errorHandlers = [];
        while (handler) {
            middleware.unshift.apply(middleware, handler.middlewares || []);
            errorHandlers.unshift.apply(errorHandlers, handler.errorHandlers || []);
            handler = handler.parent;
        }

        if (this.globals.length)
            middleware.splice.apply( middleware, [1, 0].concat( this.globals ) );

        var i = 0;
        function processNext() {
            handler = middleware[i++];
            if (!handler || i > middleware.length)
                return next();

            handler(req, res, function(err) {
                if (err)
                    return that.handleError(errorHandlers, err, req, res, next);

                processNext();
            });
        }

        processNext();
    }).bind(this);

    this.handleError = function (errorHandlers, err, req, res, next) {
        var i = 0;
        function processNext(err) {
            if (!err)
                return next();

            var handler = errorHandlers[i++];
            if (!handler || i > errorHandlers.length)
                return next(err);

            handler(err, req, res, processNext);
        }

        processNext(err);
    };

    this.match = function(req, path, method) {
        var splitPath = path.split("/");
        if (!splitPath[0])
            splitPath.shift();
        if (splitPath.length) {
            var section = sections[splitPath[0]];
            if (section && section.length) {
                var subPath = "/" + splitPath.slice(1).join("/");
                for (var i = 0; i < section.length; i++) {
                    var handler = section[i].match(req, subPath, method);
                    if (handler)
                        return handler;
                }
            }
        }

        var methodRoutes = routes[method];
        for (var i = 0; i < methodRoutes.length; i++) {
            var route = methodRoutes[i];
            if (route.match(req, path))
                return route;
        }
    };

    this.describe = function() {
        // sections and routes
        var api = {};

        if (name)
            api.name = name;

        if (description)
            api.description = description;
        api.sections = [];
        for (var key in sections) {
            for (var i=0; i < sections[key].length; i++) {
                api.sections.push(sections[key][i].describe());
            }
        }
        if (!api.sections.length)
            delete api.sections;

        api.routes = [];
        for (var method in routes) {
            for (var i=0; i < routes[method].length; i++) {
                api.routes.push(routes[method][i].describe());
            }
        }
        if (!api.routes.length)
            delete api.routes;

        return api;
    };
};<commit_msg>Fix login / error handling<commit_after>"use strict";

var url = require("url");
var Types = require("./types").Types;
var Route = require("./route");
var flatten = require("./utils").flatten;

module.exports = function Section(name, description, types) {

    types = types || new Types();
    var routes = [];
    var sections = {};
    var self = this;

    this.middlewares = [];
    this.globals = [];
    this.errorHandlers = [];
    this.name = name;

    var methods = ["head", "get", "put", "post", "delete", "patch", "upgrade", "options"];
    methods.forEach(function(method) {
        routes[method] = [];

        self[method] = (function(method, route, options, handler) {
            // options is optional
            if (typeof options == "function" || Array.isArray(options)) {
                handler = options;
                options = {};
            }
            options.method = method;
            return self._route(route, options, handler);
        }).bind(self, method);
    });
    this.del = this["delete"];

    this.registerType = types.register.bind(types);

    this.all = function(method, route, options, handler) {
        var self = this;
        var args = arguments;

        methods.forEach(function(method) {
            self[method].apply(self, args);
        });
    };

    /**
     * Insert global middleware(s) for this section: The parent section is
     * always an empty container that delegates to it's sub-sections, and
     * executes all the middelwares for that section.
     *
     * This method allows us to inject a "global" middleware that is inserted
     * *after* decodeParams and *before* all other middelwares.
     */
    this.global = function( middleware ){
        this.globals.push.apply(this.globals, flatten(middleware));
    };

    this.use = function(middleware) {
        this.middlewares.push.apply(this.middlewares, flatten(middleware));
    };

    this.error = function(middleware) {
        this.errorHandlers.push.apply(this.errorHandlers, flatten(middleware));
    };

    this._route = function(route, options, handler) {
        route = new Route(route, options, handler, types);
        route.parent = this;
        routes[route.method].push(route);
        return this;
    };

    this.section = function(name, description) {
        var section = new Section(name, description, types);
        section.parent = this;
        if (!sections[name])
            sections[name] = [];

        sections[name].push(section);
        return section;
    };

    this.getRoutes = function(){
        return routes;
    };

    /**
     * Mount an existing section on this instance.
     *
     * Note that when the first argument is omitted, the section's routes will
     * be copied onto this instance's routing table.
     *
     * @param {string} mountpoint Where to mount this secion, e.g. "/capture/"
     * @param {Section} section A frontdoor section
     */

    this.mount = function(name, section) {
        var that = this;

        if (arguments.length == 1) {
            section = arguments[0];

            if (!(section instanceof Section))
                throw new Error("Single argument to mount must be a Section!");

            var addRoutes = section.getRoutes();

            Object.keys(addRoutes).forEach(function(method) {
                var r = addRoutes[method];
                r.forEach(function(route) {
                    route.parent = that;
                })
                routes[method] = [].concat(routes[method], r);
            });

            return;
        }

        if (!sections[name])
            sections[name] = [];

        section.parent = this;
        sections[name].push(section);
    };

    /**
     * Sortcut for client-side routing without a `next`
     *
     * Allows you to omit the third argument, "next" and avoid special
     * treatment in router.js (see "wrapHandler").
     *
     * Has a variable number of argumnets: no need to wrap handlers in an array
     */
    this.on = function( path, handler ){
        var middlewares = Array.prototype.slice.call( arguments, 1 );
        handler = middlewares.shift();

        middlewares.unshift(function(req, res, next){
            handler( req, res, next );
        });

        this._route( path, { method: "get" }, middlewares );
    };

    this._rootHandler = function(req, res) {
        this.handle(req, res, function(err) {
            if (err) {
                res.statusCode = err.code || err.statusCode || 500;
                res.end(err.message || err.toString);
            } else {
                res.statusCode = 404;
                res.end("cannot " + req.method);
            }
        });
    };

    this.handle = (function(path, req, res, next) {
        var that = this;

        if (arguments.length == 2) {
            return this._rootHandler.apply(this, arguments);
        }

        if (arguments.length === 3) {
            req = arguments[0];
            res = arguments[1];
            next = arguments[2];

            if (!req.parsedUrl)
                req.parsedUrl = url.parse(req.url, true);

            path = req.parsedUrl.pathname;
        }

        req.params = req.params || {};

        var method = req.method.toLowerCase();
        if (methods.indexOf(method) == -1)
            return next();

        var handler = this.match(req, path, method);
        if (!handler)
            return next();

        var middleware = [];
        var errorHandlers = [];
        while (handler) {
            middleware.unshift.apply(middleware, handler.middlewares || []);
            errorHandlers.unshift.apply(errorHandlers, handler.errorHandlers || []);
            handler = handler.parent;
        }

        if (this.globals.length)
            middleware.splice.apply( middleware, [1, 0].concat( this.globals ) );

        var i = 0;
        function processNext() {
            handler = middleware[i++];
            if (!handler || i > middleware.length)
                return next();

            handler(req, res, function(err) {
                if (err)
                    return that.handleError(errorHandlers, err, req, res, next);

                processNext();
            });
        }

        processNext();
    }).bind(this);

    this.handleError = function (errorHandlers, err, req, res, next) {
        var i = 0;
        function processNext(err) {
            if (!err)
                return next();

            var handler = errorHandlers[i++];
            if (!handler || i > errorHandlers.length)
                return next(err);

            handler(err, req, res, processNext);
        }

        processNext(err);
    };

    this.match = function(req, path, method) {
        var splitPath = path.split("/");
        if (!splitPath[0])
            splitPath.shift();
        if (splitPath.length) {
            var section = sections[splitPath[0]];
            if (section && section.length) {
                var subPath = "/" + splitPath.slice(1).join("/");
                for (var i = 0; i < section.length; i++) {
                    var handler = section[i].match(req, subPath, method);
                    if (handler)
                        return handler;
                }
            }
        }

        var methodRoutes = routes[method];
        for (var i = 0; i < methodRoutes.length; i++) {
            var route = methodRoutes[i];
            if (route.match(req, path))
                return route;
        }
    };

    this.describe = function() {
        // sections and routes
        var api = {};

        if (name)
            api.name = name;

        if (description)
            api.description = description;
        api.sections = [];
        for (var key in sections) {
            for (var i=0; i < sections[key].length; i++) {
                api.sections.push(sections[key][i].describe());
            }
        }
        if (!api.sections.length)
            delete api.sections;

        api.routes = [];
        for (var method in routes) {
            for (var i=0; i < routes[method].length; i++) {
                api.routes.push(routes[method][i].describe());
            }
        }
        if (!api.routes.length)
            delete api.routes;

        return api;
    };
};<|endoftext|>


<commit_before>// Copyright © 2015-2019 Esko Luontola
// This software is released under the Apache License 2.0.
// The license text is at http://www.apache.org/licenses/LICENSE-2.0

import React, {useState} from "react";
import {addUser, getCongregationById} from "../api";
import {Link} from "@reach/router";
import {ErrorMessage, Field, Form, Formik} from "formik";
import sortBy from "lodash/sortBy";
import styles from "./UsersPage.css";

const IdentityProvider = ({user}) => {
  const sub = user.sub || '';
  const nickname = user.nickname || sub;
  if (sub.startsWith('google-oauth2|')) {
    return `Google (${nickname})`;
  }
  if (sub.startsWith('facebook|')) {
    return `Facebook (${nickname})`;
  }
  return sub;
};

const UsersPage = ({congregationId}) => {
  const [newUser, setNewUser] = useState(null);
  const congregation = getCongregationById(congregationId);
  const joinPageUrl = `${location.protocol}//${location.host}/join`;
  // show the new user first for better visibility
  const users = sortBy(congregation.users, user => user.id !== newUser);
  return (
    <Formik
      initialValues={{
        userId: '',
      }}
      validate={values => {
        let errors = {};
        if (!values.userId) {
          errors.userId = 'User ID is required.';
        }
        return errors;
      }}
      onSubmit={async (values, {setSubmitting, resetForm}) => {
        try {
          await addUser(congregation.id, values.userId);
          // changing state is needed to trigger re-rendering with the updated user list
          setNewUser(values.userId);
          resetForm();
        } catch (e) {
          console.error('Form submit failed:', e);
          alert(e);
        } finally {
          setSubmitting(false);
        }
      }}
    >{({isSubmitting}) => (
      <>

<Link to="..">{congregation.name}</Link>: Users

To add users to this congregation, ask them to visit <Link to="/join">{joinPageUrl}</Link> and tell you
          their user ID from that page. You can then input their user ID to the following form.

        <Form className="pure-form pure-form-aligned">
          <fieldset>

              User ID
              <Field name="userId" id="userId" type="text" autoComplete="off"/>
              <ErrorMessage name="userId" component="span" className="pure-form-message-inline"/>

              <button type="submit"
                      disabled={isSubmitting}
                      className="pure-button pure-button-primary">
                Add User
              </button>
              {' '}
              <Link to=".." className="pure-button">Cancel</Link>

          </fieldset>
        </Form>

            Name
            Email
            Login Method

          {users.map(user => (

                {user.picture && }

              {user.name || user.id}
              {user.email} {(user.email && !user.emailVerified) && (Unverified)}
              <IdentityProvider user={user}/>

          ))}

      </>
    )}
    </Formik>
  );
};

export default UsersPage;
<commit_msg>🔥 Remove nickname from identity provider info<commit_after>// Copyright © 2015-2019 Esko Luontola
// This software is released under the Apache License 2.0.
// The license text is at http://www.apache.org/licenses/LICENSE-2.0

import React, {useState} from "react";
import {addUser, getCongregationById} from "../api";
import {Link} from "@reach/router";
import {ErrorMessage, Field, Form, Formik} from "formik";
import sortBy from "lodash/sortBy";
import styles from "./UsersPage.css";

const IdentityProvider = ({user}) => {
  const sub = user.sub || '';
  if (sub.startsWith('google-oauth2|')) {
    return 'Google';
  }
  if (sub.startsWith('facebook|')) {
    return 'Facebook';
  }
  return sub;
};

const UsersPage = ({congregationId}) => {
  const [newUser, setNewUser] = useState(null);
  const congregation = getCongregationById(congregationId);
  const joinPageUrl = `${location.protocol}//${location.host}/join`;
  // show the new user first for better visibility
  const users = sortBy(congregation.users, user => user.id !== newUser);
  return (
    <Formik
      initialValues={{
        userId: '',
      }}
      validate={values => {
        let errors = {};
        if (!values.userId) {
          errors.userId = 'User ID is required.';
        }
        return errors;
      }}
      onSubmit={async (values, {setSubmitting, resetForm}) => {
        try {
          await addUser(congregation.id, values.userId);
          // changing state is needed to trigger re-rendering with the updated user list
          setNewUser(values.userId);
          resetForm();
        } catch (e) {
          console.error('Form submit failed:', e);
          alert(e);
        } finally {
          setSubmitting(false);
        }
      }}
    >{({isSubmitting}) => (
      <>

<Link to="..">{congregation.name}</Link>: Users

To add users to this congregation, ask them to visit <Link to="/join">{joinPageUrl}</Link> and tell you
          their user ID from that page. You can then input their user ID to the following form.

        <Form className="pure-form pure-form-aligned">
          <fieldset>

              User ID
              <Field name="userId" id="userId" type="text" autoComplete="off"/>
              <ErrorMessage name="userId" component="span" className="pure-form-message-inline"/>

              <button type="submit"
                      disabled={isSubmitting}
                      className="pure-button pure-button-primary">
                Add User
              </button>
              {' '}
              <Link to=".." className="pure-button">Cancel</Link>

          </fieldset>
        </Form>

            Name
            Email
            Login Method

          {users.map(user => (

                {user.picture && }

              {user.name || user.id}
              {user.email} {(user.email && !user.emailVerified) && (Unverified)}
              <IdentityProvider user={user}/>

          ))}

      </>
    )}
    </Formik>
  );
};

export default UsersPage;
<|endoftext|>


<commit_before>#!/usr/bin/env node

var util = require('util'),
    http = require('http'),
    fs = require('fs'),
    url = require('url'),
    events = require('events');

var DEFAULT_PORT = 8000;

function main(argv) {
  new HttpServer({
    'GET': createServlet(StaticServlet),
    'HEAD': createServlet(StaticServlet)
  }).start(Number(argv[2]) || DEFAULT_PORT);
}

function escapeHtml(value) {
  return value.toString().
    replace('<', '<').
    replace('>', '>').
    replace('"', '"');
}

function createServlet(Class) {
  var servlet = new Class();
  return servlet.handleRequest.bind(servlet);
}

/**
 * An Http server implementation that uses a map of methods to decide
 * action routing.
 *
 * @param {Object} Map of method => Handler function
 */
function HttpServer(handlers) {
  this.handlers = handlers;
  this.server = http.createServer(this.handleRequest_.bind(this));
}

HttpServer.prototype.start = function(port) {
  this.port = port;
  this.server.listen(port);
  util.puts('Http Server running at http://localhost:' + port + '/');
};

HttpServer.prototype.parseUrl_ = function(urlString) {
  var parsed = url.parse(urlString);
  parsed.pathname = url.resolve('/', parsed.pathname);
  return url.parse(url.format(parsed), true);
};

HttpServer.prototype.handleRequest_ = function(req, res) {
  var logEntry = req.method + ' ' + req.url;
  if (req.headers['user-agent']) {
    logEntry += ' ' + req.headers['user-agent'];
  }
  util.puts(logEntry);
  req.url = this.parseUrl_(req.url);
  var handler = this.handlers[req.method];
  if (!handler) {
    res.writeHead(501);
    res.end();
  } else {
    handler.call(this, req, res);
  }
};

/**
 * Handles static content.
 */
function StaticServlet() {}

StaticServlet.MimeMap = {
  'txt': 'text/plain',
  'html': 'text/html',
  'css': 'text/css',
  'xml': 'application/xml',
  'json': 'application/json',
  'js': 'application/javascript',
  'jpg': 'image/jpeg',
  'jpeg': 'image/jpeg',
  'gif': 'image/gif',
  'png': 'image/png',
  'svg': 'image/svg+xml'
};

StaticServlet.prototype.handleRequest = function(req, res) {
  var self = this;
  var path = ('./' + req.url.pathname).replace('//','/').replace(/%(..)/g, function(match, hex){
    return String.fromCharCode(parseInt(hex, 16));
  });
  var parts = path.split('/');
  if (parts[parts.length-1].charAt(0) === '.')
    return self.sendForbidden_(req, res, path);
  fs.stat(path, function(err, stat) {
    if (err)
      return self.sendMissing_(req, res, path);
    if (stat.isDirectory())
      return self.sendDirectory_(req, res, path);
    return self.sendFile_(req, res, path);
  });
}

StaticServlet.prototype.sendError_ = function(req, res, error) {
  res.writeHead(500, {
      'Content-Type': 'text/html'
  });
  res.write('<!doctype html>\n');
  res.write('<title>Internal Server Error</title>\n');
  res.write('
Internal Server Error
');
  res.write('
' + escapeHtml(util.inspect(error)) + '
');
  util.puts('500 Internal Server Error');
  util.puts(util.inspect(error));
};

StaticServlet.prototype.sendMissing_ = function(req, res, path) {
  path = path.substring(1);
  res.writeHead(404, {
      'Content-Type': 'text/html'
  });
  res.write('<!doctype html>\n');
  res.write('<title>404 Not Found</title>\n');
  res.write('
Not Found
');
  res.write(
    '
The requested URL ' +
    escapeHtml(path) +
    ' was not found on this server.
'
  );
  res.end();
  util.puts('404 Not Found: ' + path);
};

StaticServlet.prototype.sendForbidden_ = function(req, res, path) {
  path = path.substring(1);
  res.writeHead(403, {
      'Content-Type': 'text/html'
  });
  res.write('<!doctype html>\n');
  res.write('<title>403 Forbidden</title>\n');
  res.write('
Forbidden
');
  res.write(
    '
You do not have permission to access ' +
    escapeHtml(path) + ' on this server.
'
  );
  res.end();
  util.puts('403 Forbidden: ' + path);
};

StaticServlet.prototype.sendRedirect_ = function(req, res, redirectUrl) {
  res.writeHead(301, {
      'Content-Type': 'text/html',
      'Location': redirectUrl
  });
  res.write('<!doctype html>\n');
  res.write('<title>301 Moved Permanently</title>\n');
  res.write('
Moved Permanently
');
  res.write(
    '
The document has moved here.
'
  );
  res.end();
  util.puts('301 Moved Permanently: ' + redirectUrl);
};

StaticServlet.prototype.sendFile_ = function(req, res, path) {
  var self = this;
  var file = fs.createReadStream(path);
  res.writeHead(200, {
    'Content-Type': StaticServlet.
      MimeMap[path.split('.').pop()] || 'text/plain'
  });
  if (req.method === 'HEAD') {
    res.end();
  } else {
    file.on('data', res.write.bind(res));
    file.on('close', function() {
      res.end();
    });
    file.on('error', function(error) {
      self.sendError_(req, res, error);
    });
  }
};

StaticServlet.prototype.sendDirectory_ = function(req, res, path) {
  var self = this;
  if (path.match(/[^\/]$/)) {
    req.url.pathname += '/';
    var redirectUrl = url.format(url.parse(url.format(req.url)));
    return self.sendRedirect_(req, res, redirectUrl);
  }
  fs.readdir(path, function(err, files) {
    if (err)
      return self.sendError_(req, res, error);

    if (!files.length)
      return self.writeDirectoryIndex_(req, res, path, []);

    var remaining = files.length;
    files.forEach(function(fileName, index) {
      fs.stat(path + '/' + fileName, function(err, stat) {
        if (err)
          return self.sendError_(req, res, err);
        if (stat.isDirectory()) {
          files[index] = fileName + '/';
        }
        if (!(--remaining))
          return self.writeDirectoryIndex_(req, res, path, files);
      });
    });
  });
};

StaticServlet.prototype.writeDirectoryIndex_ = function(req, res, path, files) {
  path = path.substring(1);
  res.writeHead(200, {
    'Content-Type': 'text/html'
  });
  if (req.method === 'HEAD') {
    res.end();
    return;
  }
  res.write('<!doctype html>\n');
  res.write('<title>' + escapeHtml(path) + '</title>\n');
  res.write('\n');
  res.write('
Directory: ' + escapeHtml(path) + '
');
  res.write('
');
  files.forEach(function(fileName) {
    if (fileName.charAt(0) !== '.') {
      res.write('
' +
        escapeHtml(fileName) + '
');
    }
  });
  res.write('
');
  res.end();
};

// Must be last,
main(process.argv);
<commit_msg>cleanup<commit_after><|endoftext|>


<commit_before>var sha1 = require('node-sha1');
var q = require('q');

var utils = require('./../utils');
var request = require('../request');
var conf = require('../../conf');

exports.uploadFile = function(b2, args) {
    var uploadUrl = args.uploadUrl;
    var uploadAuthToken = args.uploadAuthToken;
    var filename = args.filename;
    var data = args.data;

    var options = {
        url: uploadUrl,
        method: 'POST',
        headers: {
            Authorization: uploadAuthToken,
            'Content-Type': 'b2/x-auto',
            'X-Bz-File-Name': filename,
            'X-Bz-Content-Sha1': data ? sha1(data) : null
        },
        body: data
    };
    return request.sendRequest(options);
};

exports.listFileNames = function(b2, args) {
    var bucketId = args.bucketId;
    var startFileName = args.startFileName;
    var maxFileCount = args.maxFileCount;

    var options = {
        url: getListFilesUrl(b2),
        method: 'POST',
        headers: utils.getAuthHeaderObjectWithToken(b2),
        body: JSON.stringify({
            bucketId: bucketId,
            startFileName: startFileName ? startFileName : '',
            maxFileCount: maxFileCount ? maxFileCount : 100
        })
    };
    return request.sendRequest(options);
};

exports.listFileVersions = function(b2, args) {
    var bucketId = args.bucketId;
    var startFileName = args.startFileName;
    var maxFileCount = args.maxFileCount;

    var options = {
        url: getListFileVersionsUrl(b2),
        method: 'POST',
        headers: utils.getAuthHeaderObjectWithToken(b2),
        body: JSON.stringify({
            bucketId: bucketId,
            startFileName: startFileName ? startFileName : '',
            maxFileCount: maxFileCount ? maxFileCount : 100
        })
    };
    return request.sendRequest(options);
};

exports.hideFile = function(b2, args) {
    var bucketId = args.bucketId;
    var fileName = args.fileName;

    var options = {
        url: getHideFileUrl(b2),
        method: 'POST',
        headers: utils.getAuthHeaderObjectWithToken(b2),
        body: JSON.stringify({
            bucketId: bucketId,
            fileName: fileName
        })
    };
    return request.sendRequest(options);
};

exports.getFileInfo = function(b2, fileId) {
    var options = {
        url: getFileInfoUrl(b2),
        method: 'POST',
        headers: utils.getAuthHeaderObjectWithToken(b2),
        body: JSON.stringify({
            fileId: fileId
        })
    };
    return request.sendRequest(options);
};

exports.downloadFileByName = function(b2, args) {
    var bucketName = args.bucketName;
    var fileName = args.fileName;

    var options = {
        url: getDownloadFileByNameUrl(b2, bucketName, fileName),
        headers: utils.getAuthHeaderObjectWithToken(b2)
    };

    var deferred = q.defer();

    var requestInstance = request.getInstance();
    requestInstance(options, utils.getProcessFileSuccess(deferred, processDownloadResponse));

    return deferred.promise;
};

exports.downloadFileById = function(b2, fileId) {
    var options = {
        url: getDownloadFileByIdUrl(b2),
        qs: {
            fileId: fileId
        },
        headers: utils.getAuthHeaderObjectWithToken(b2)
    };

    var deferred = q.defer();

    var requestInstance = request.getInstance();
    requestInstance(options, utils.getProcessFileSuccess(deferred, processDownloadResponse));

    return deferred.promise;
};

exports.deleteFileVersion = function(b2, args) {
    var fileId = args.fileId;
    var fileName = args.fileName;

    var options = {
        url: getDeleteFileVersionUrl(b2),
        method: 'POST',
        headers: utils.getAuthHeaderObjectWithToken(b2),
        body: JSON.stringify({
            fileId: fileId,
            fileName: fileName
        })
    };

    return request.sendRequest(options);
};

function processDownloadResponse(response, body) {
    var headers = [
        { key: 'X-Bz-File-Id', name: 'fileId' },
        { key: 'X-Bz-File-Name', name: 'filename' },
        { key: 'X-Bz-Content-Sha1', name: 'sha1' }
    ];

    var obj = { data: body };

    headers.forEach(processHeader);

    function processHeader(headersMapping) {
        var key = headersMapping.key.toLowerCase();
        var name = headersMapping.name;
        obj[name] = response.headers[key];
    }

    return obj;
}

function getListFilesUrl(b2) {
    return getApiUrl(b2) + '/b2_list_file_names';
}

function getListFileVersionsUrl(b2) {
    return getApiUrl(b2) + '/b2_list_file_versions';
}

function getHideFileUrl(b2) {
    return getApiUrl(b2) + '/b2_hide_file';
}

function getFileInfoUrl(b2) {
    return getApiUrl(b2) + '/b2_get_file_info';
}

function getDownloadFileByNameUrl(b2, bucketName, fileName) {
    return b2.downloadUrl + '/file/' + bucketName + '/' + fileName;
}

function getDownloadFileByIdUrl(b2) {
    return b2.downloadUrl + conf.API_VERSION_URL + '/b2_download_file_by_id';
}

function getDeleteFileVersionUrl(b2) {
    return getApiUrl(b2) + '/b2_delete_file_version';
}

function getApiUrl(b2) {
    return b2.apiUrl + conf.API_VERSION_URL;
}
<commit_msg>filename string should be URL encoded<commit_after>var sha1 = require('node-sha1');
var q = require('q');

var utils = require('./../utils');
var request = require('../request');
var conf = require('../../conf');

exports.uploadFile = function(b2, args) {
    var uploadUrl = args.uploadUrl;
    var uploadAuthToken = args.uploadAuthToken;
    var filename = encodeURIComponent(args.filename);
    var data = args.data;

    var options = {
        url: uploadUrl,
        method: 'POST',
        headers: {
            Authorization: uploadAuthToken,
            'Content-Type': 'b2/x-auto',
            'X-Bz-File-Name': filename,
            'X-Bz-Content-Sha1': data ? sha1(data) : null
        },
        body: data
    };
    return request.sendRequest(options);
};

exports.listFileNames = function(b2, args) {
    var bucketId = args.bucketId;
    var startFileName = args.startFileName;
    var maxFileCount = args.maxFileCount;

    var options = {
        url: getListFilesUrl(b2),
        method: 'POST',
        headers: utils.getAuthHeaderObjectWithToken(b2),
        body: JSON.stringify({
            bucketId: bucketId,
            startFileName: startFileName ? startFileName : '',
            maxFileCount: maxFileCount ? maxFileCount : 100
        })
    };
    return request.sendRequest(options);
};

exports.listFileVersions = function(b2, args) {
    var bucketId = args.bucketId;
    var startFileName = args.startFileName;
    var maxFileCount = args.maxFileCount;

    var options = {
        url: getListFileVersionsUrl(b2),
        method: 'POST',
        headers: utils.getAuthHeaderObjectWithToken(b2),
        body: JSON.stringify({
            bucketId: bucketId,
            startFileName: startFileName ? startFileName : '',
            maxFileCount: maxFileCount ? maxFileCount : 100
        })
    };
    return request.sendRequest(options);
};

exports.hideFile = function(b2, args) {
    var bucketId = args.bucketId;
    var fileName = args.fileName;

    var options = {
        url: getHideFileUrl(b2),
        method: 'POST',
        headers: utils.getAuthHeaderObjectWithToken(b2),
        body: JSON.stringify({
            bucketId: bucketId,
            fileName: fileName
        })
    };
    return request.sendRequest(options);
};

exports.getFileInfo = function(b2, fileId) {
    var options = {
        url: getFileInfoUrl(b2),
        method: 'POST',
        headers: utils.getAuthHeaderObjectWithToken(b2),
        body: JSON.stringify({
            fileId: fileId
        })
    };
    return request.sendRequest(options);
};

exports.downloadFileByName = function(b2, args) {
    var bucketName = args.bucketName;
    var fileName = args.fileName;

    var options = {
        url: getDownloadFileByNameUrl(b2, bucketName, fileName),
        headers: utils.getAuthHeaderObjectWithToken(b2)
    };

    var deferred = q.defer();

    var requestInstance = request.getInstance();
    requestInstance(options, utils.getProcessFileSuccess(deferred, processDownloadResponse));

    return deferred.promise;
};

exports.downloadFileById = function(b2, fileId) {
    var options = {
        url: getDownloadFileByIdUrl(b2),
        qs: {
            fileId: fileId
        },
        headers: utils.getAuthHeaderObjectWithToken(b2)
    };

    var deferred = q.defer();

    var requestInstance = request.getInstance();
    requestInstance(options, utils.getProcessFileSuccess(deferred, processDownloadResponse));

    return deferred.promise;
};

exports.deleteFileVersion = function(b2, args) {
    var fileId = args.fileId;
    var fileName = args.fileName;

    var options = {
        url: getDeleteFileVersionUrl(b2),
        method: 'POST',
        headers: utils.getAuthHeaderObjectWithToken(b2),
        body: JSON.stringify({
            fileId: fileId,
            fileName: fileName
        })
    };

    return request.sendRequest(options);
};

function processDownloadResponse(response, body) {
    var headers = [
        { key: 'X-Bz-File-Id', name: 'fileId' },
        { key: 'X-Bz-File-Name', name: 'filename' },
        { key: 'X-Bz-Content-Sha1', name: 'sha1' }
    ];

    var obj = { data: body };

    headers.forEach(processHeader);

    function processHeader(headersMapping) {
        var key = headersMapping.key.toLowerCase();
        var name = headersMapping.name;
        obj[name] = response.headers[key];
    }

    return obj;
}

function getListFilesUrl(b2) {
    return getApiUrl(b2) + '/b2_list_file_names';
}

function getListFileVersionsUrl(b2) {
    return getApiUrl(b2) + '/b2_list_file_versions';
}

function getHideFileUrl(b2) {
    return getApiUrl(b2) + '/b2_hide_file';
}

function getFileInfoUrl(b2) {
    return getApiUrl(b2) + '/b2_get_file_info';
}

function getDownloadFileByNameUrl(b2, bucketName, fileName) {
    return b2.downloadUrl + '/file/' + bucketName + '/' + fileName;
}

function getDownloadFileByIdUrl(b2) {
    return b2.downloadUrl + conf.API_VERSION_URL + '/b2_download_file_by_id';
}

function getDeleteFileVersionUrl(b2) {
    return getApiUrl(b2) + '/b2_delete_file_version';
}

function getApiUrl(b2) {
    return b2.apiUrl + conf.API_VERSION_URL;
}
<|endoftext|>


<commit_before>//----------------------------------------------------------------------
// AdalJS v1.0.7
// @preserve Copyright (c) Microsoft Open Technologies, Inc.
// All Rights Reserved
// Apache License 2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//----------------------------------------------------------------------
'use strict';

if (typeof module !== 'undefined' && module.exports) {
    module.exports.inject = function (conf) {
        return new AuthenticationContext(conf);
    };
}

(function () {
    // ============= Angular modules- Start =============
    if (angular) {

        var AdalModule = angular.module('AdalAngular', []);

        AdalModule.provider('adalAuthenticationService', function () {
            var _adal = null;
            var _oauthData = { isAuthenticated: false, userName: '', loginError: '', profile: '' };
            var _isRenewingToken = false;
            var _cachedTokens = { };

            var updateDataFromCache = function (resource) {
                // only cache lookup here to not interrupt with events
                var token = _adal.getCachedToken(resource);
                _oauthData.isAuthenticated = token !== null && token.length > 0;
                var user = _adal.getCachedUser() || { userName: '' };
                _oauthData.userName = user.userName;
                _oauthData.profile = user.profile;
                _oauthData.loginError = _adal.getLoginError();
            };

            this.init = function (configOptions, httpProvider) {
                if (configOptions) {
                    // redirect and logout_redirect are set to current location by default
                    var existingHash = window.location.hash;
                    var pathDefault = window.location.href;
                    if (existingHash) {
                        pathDefault = pathDefault.replace(existingHash, '');
                    }
                    configOptions.redirectUri = configOptions.redirectUri || pathDefault;
                    configOptions.postLogoutRedirectUri = configOptions.postLogoutRedirectUri || pathDefault;

                    if (httpProvider && httpProvider.interceptors) {
                        httpProvider.interceptors.push('ProtectedResourceInterceptor');
                    }

                    // create instance with given config
                    _adal = new AuthenticationContext(configOptions);
                } else {
                    throw new Error('You must set configOptions, when calling init');
                }

                // loginresource is used to set authenticated status
                updateDataFromCache(_adal.config.loginResource);
            };

            // special function that exposes methods in Angular controller
            // $rootScope, $window, $q, $location, $timeout are injected by Angular
            this.$get = ['$rootScope', '$window', '$q', '$location', '$timeout', function ($rootScope, $window, $q, $location, $timeout) {

                var locationChangeHandler = function () {
                    var hash = $window.location.hash;

                    if (_adal.isCallback(hash)) {
                        // callback can come from login or iframe request

                        var requestInfo = _adal.getRequestInfo(hash);
                        _adal.saveTokenFromHash(requestInfo);

                        if ($location.$$html5) {
                            $window.location = $window.location.origin + $window.location.pathname;
                        } else {
                            $window.location.hash = '';
                        }

                        if (requestInfo.requestType !== _adal.REQUEST_TYPE.LOGIN) {
                            _adal.callback = $window.parent.AuthenticationContext().callback;
                            if (requestInfo.requestType === _adal.REQUEST_TYPE.RENEW_TOKEN) {
                                _adal.callback = $window.parent.callBackMappedToRenewStates[requestInfo.stateResponse];
                            }
                        }

                        // Return to callback if it is send from iframe
                        if (requestInfo.stateMatch) {
                            if (typeof _adal.callback === 'function') {
                                // Call within the same context without full page redirect keeps the callback
                                if (requestInfo.requestType === _adal.REQUEST_TYPE.RENEW_TOKEN) {
                                    // Idtoken or Accestoken can be renewed
                                    if (requestInfo.parameters['access_token']) {
                                        _adal.callback(_adal._getItem(_adal.CONSTANTS.STORAGE.ERROR_DESCRIPTION), requestInfo.parameters['access_token']);
                                        return;
                                    } else if (requestInfo.parameters['id_token']) {
                                        _adal.callback(_adal._getItem(_adal.CONSTANTS.STORAGE.ERROR_DESCRIPTION), requestInfo.parameters['id_token']);
                                        return;
                                    }
                                }
                            } else {
                                // normal full login redirect happened on the page
                                updateDataFromCache(_adal.config.loginResource);
                                if (_oauthData.userName) {
                                    //IDtoken is added as token for the app
                                    $timeout(function () {
                                        updateDataFromCache(_adal.config.loginResource);
                                        $rootScope.userInfo = _oauthData;
                                        // redirect to login requested page
                                        var loginStartPage = _adal._getItem(_adal.CONSTANTS.STORAGE.START_PAGE);
                                        if (loginStartPage) {
                                            $location.path(loginStartPage);
                                        }
                                    }, 1);
                                    $rootScope.$broadcast('adal:loginSuccess');
                                } else {
                                    $rootScope.$broadcast('adal:loginFailure', _adal._getItem(_adal.CONSTANTS.STORAGE.ERROR_DESCRIPTION));
                                }
                            }
                        }
                    } else {
                        // No callback. App resumes after closing or moving to new page.
                        // Check token and username
                        updateDataFromCache(_adal.config.loginResource);
                        if (!_adal._renewActive && !_oauthData.isAuthenticated && _oauthData.userName) {
                            if (!_adal._getItem(_adal.CONSTANTS.STORAGE.FAILED_RENEW)) {
                                // Idtoken is expired or not present
                                _isRenewingToken = true;
                                _adal.acquireToken(_adal.config.loginResource, function (error, tokenOut) {
                                    if (error) {
                                        _isRenewingToken = false;
                                        $rootScope.$broadcast('adal:loginFailure', 'auto renew failure ' + error);
                                    } else {
                                        _isRenewingToken = false;
                                        if (tokenOut) {
                                            _oauthData.isAuthenticated = true;
                                            $rootScope.$broadcast('adal:tokenRenewSuccess', _adal.config.loginResource);
                                        }
                                    }
                                });
                            }
                        }
                    }

                    $timeout(function () {
                        updateDataFromCache(_adal.config.loginResource);
                        $rootScope.userInfo = _oauthData;
                    }, 1);
                };

                var isInIFrame = function () {
                    try {
                        return window.self !== window.top;
                    } catch (e) {
                        console && console.error('isInIFrame: Unexpected error:', e);
                        return true;
                    }
                }

                var loginHandler = function () {
                    _adal.info('Login event for:' + $location.$$path);
                    if (_adal.config && _adal.config.localLoginUrl) {
                        $location.path(_adal.config.localLoginUrl);
                    } else {
                        // directly start login flow
                        _adal._saveItem(_adal.CONSTANTS.STORAGE.START_PAGE, $location.$$path);
                        _adal.info('Start login at:' + window.location.href);
                        $rootScope.$broadcast('adal:loginRedirect');
                        _adal.login();
                    }
                };

                function isADLoginRequired(route, global) {
                    return global.requireADLogin ? route.requireADLogin !== false : !!route.requireADLogin;
                }

                var routeChangeHandler = function (e, nextRoute) {
                    if (nextRoute && nextRoute.$$route && isADLoginRequired(nextRoute.$$route, _adal.config)) {
                        if (!_oauthData.isAuthenticated && !isInIFrame() && !_isRenewingToken) {
                            _adal.info('Route change event for:' + $location.$$path);
                            loginHandler();
                        }
                    }
                };

                var stateChangeHandler = function (e, nextRoute) {
                    if (nextRoute && isADLoginRequired(nextRoute, _adal.config)) {
                        if (!_oauthData.isAuthenticated && !isInIFrame() && !_isRenewingToken) {
                            _adal.info('State change event for:' + $location.$$path);
                            loginHandler();
                        }
                    }
                };

                // Route change event tracking to receive fragment and also auto renew tokens
                $rootScope.$on('$routeChangeStart', routeChangeHandler);

                $rootScope.$on('$stateChangeStart', stateChangeHandler);

                $rootScope.$on('$locationChangeStart', locationChangeHandler);

                updateDataFromCache(_adal.config.loginResource);
                $rootScope.userInfo = _oauthData;

                return {
                    // public methods will be here that are accessible from Controller
                    config: _adal.config,
                    login: function () {
                        _adal.login();
                    },
                    loginInProgress: function () {
                        return _adal.loginInProgress();
                    },
                    logOut: function () {
                        _adal.logOut();
                        //call signout related method
                    },
                    getCachedToken: function (resource) {
                        return _adal.getCachedToken(resource);
                    },
                    userInfo: _oauthData,
                    acquireToken: function (resource) {
                        // automated token request call
                        var deferred = $q.defer();
                        _cachedTokens[resource]= _adal.getCachedToken(resource);
                        _adal.acquireToken(resource, function (error, tokenOut) {
                            if (error) {
                                _adal.error('Error when acquiring token for resource: ' + resource, error);
                                deferred.reject(error);
                            } else {
                                deferred.resolve(tokenOut);
                                if (_cachedTokens[resource] !== tokenOut) {
                                    $rootScope.$broadcast('adal:tokenRenewSuccess', resource);
                                    _cachedTokens[resource] = tokenOut;
                                }
                            }
                        });

                        return deferred.promise;
                    },
                    getUser: function () {
                        var deferred = $q.defer();
                        _adal.getUser(function (error, user) {
                            if (error) {
                                _adal.error('Error when getting user', error);
                                deferred.reject(error);
                            } else {
                                deferred.resolve(user);
                            }
                        });

                        return deferred.promise;
                    },
                    getResourceForEndpoint: function (endpoint) {
                        return _adal.getResourceForEndpoint(endpoint);
                    },
                    clearCache: function () {
                        _adal.clearCache();
                    },
                    clearCacheForResource: function (resource) {
                        _adal.clearCacheForResource(resource);
                    },
                    info: function(message) {
                        _adal.info(message);
                    },
                    verbose: function(message) {
                        _adal.verbose(message);
                    }
                };
            }];
        });

        // Interceptor for http if needed
        AdalModule.factory('ProtectedResourceInterceptor', ['adalAuthenticationService', '$q', '$rootScope', function (authService, $q, $rootScope) {

            return {
                request: function (config) {
                    if (config) {

                        // This interceptor needs to load service, but dependeny definition causes circular reference error.
                        // Loading with injector is suggested at github. https://github.com/angular/angular.js/issues/2367

                        config.headers = config.headers || {};

                        var resource = authService.getResourceForEndpoint(config.url);
                        if (resource === null) {
                            return config;
                        }

                        var tokenStored = authService.getCachedToken(resource);
                        var isEndpoint = false;
                        if (tokenStored) {
                            authService.info('Token is avaliable for this url ' + config.url);
                            // check endpoint mapping if provided
                            config.headers.Authorization = 'Bearer ' + tokenStored;
                            return config;
                        } else {

                            if (authService.config) {
                                for (var endpointUrl in authService.config.endpoints) {
                                    if (config.url.indexOf(endpointUrl) > -1) {
                                        isEndpoint = true;
                                    }
                                }
                            }

                            // Cancel request if login is starting
                            if (authService.loginInProgress()) {
                                authService.info('login already start.');
                                return $q.reject();
                            } else if (authService.config && isEndpoint) {
                                // external endpoints
                                // delayed request to return after iframe completes
                                var delayedRequest = $q.defer();
                                authService.acquireToken(resource).then(function (token) {
                                    authService.verbose('Token is avaliable');
                                    config.headers.Authorization = 'Bearer ' + token;
                                    delayedRequest.resolve(config);
                            }, function (err) {
                                delayedRequest.reject(err);
                            });

                                return delayedRequest.promise;
                            }
                        }

                        return config;
                    }
                },
                responseError: function (rejection) {
                    authService.info('Getting error in the response');
                    if (rejection && rejection.status === 401) {
                        var resource = authService.getResourceForEndpoint(rejection.config.url);
                        authService.clearCacheForResource(resource);
                        $rootScope.$broadcast('adal:notAuthorized', rejection, resource);
                    }

                    return $q.reject(rejection);
                }
            };
        }]);
    } else {
        console.error('Angular.JS is not included');
    }
}());
<commit_msg>distinguish tokenRenewFailure<commit_after>//----------------------------------------------------------------------
// AdalJS v1.0.7
// @preserve Copyright (c) Microsoft Open Technologies, Inc.
// All Rights Reserved
// Apache License 2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//----------------------------------------------------------------------
'use strict';

if (typeof module !== 'undefined' && module.exports) {
    module.exports.inject = function (conf) {
        return new AuthenticationContext(conf);
    };
}

(function () {
    // ============= Angular modules- Start =============
    if (angular) {

        var AdalModule = angular.module('AdalAngular', []);

        AdalModule.provider('adalAuthenticationService', function () {
            var _adal = null;
            var _oauthData = { isAuthenticated: false, userName: '', loginError: '', profile: '' };
            var _isRenewingToken = false;
            var _cachedTokens = { };

            var updateDataFromCache = function (resource) {
                // only cache lookup here to not interrupt with events
                var token = _adal.getCachedToken(resource);
                _oauthData.isAuthenticated = token !== null && token.length > 0;
                var user = _adal.getCachedUser() || { userName: '' };
                _oauthData.userName = user.userName;
                _oauthData.profile = user.profile;
                _oauthData.loginError = _adal.getLoginError();
            };

            this.init = function (configOptions, httpProvider) {
                if (configOptions) {
                    // redirect and logout_redirect are set to current location by default
                    var existingHash = window.location.hash;
                    var pathDefault = window.location.href;
                    if (existingHash) {
                        pathDefault = pathDefault.replace(existingHash, '');
                    }
                    configOptions.redirectUri = configOptions.redirectUri || pathDefault;
                    configOptions.postLogoutRedirectUri = configOptions.postLogoutRedirectUri || pathDefault;

                    if (httpProvider && httpProvider.interceptors) {
                        httpProvider.interceptors.push('ProtectedResourceInterceptor');
                    }

                    // create instance with given config
                    _adal = new AuthenticationContext(configOptions);
                } else {
                    throw new Error('You must set configOptions, when calling init');
                }

                // loginresource is used to set authenticated status
                updateDataFromCache(_adal.config.loginResource);
            };

            // special function that exposes methods in Angular controller
            // $rootScope, $window, $q, $location, $timeout are injected by Angular
            this.$get = ['$rootScope', '$window', '$q', '$location', '$timeout', function ($rootScope, $window, $q, $location, $timeout) {

                var locationChangeHandler = function () {
                    var hash = $window.location.hash;

                    if (_adal.isCallback(hash)) {
                        // callback can come from login or iframe request

                        var requestInfo = _adal.getRequestInfo(hash);
                        _adal.saveTokenFromHash(requestInfo);

                        if ($location.$$html5) {
                            $window.location = $window.location.origin + $window.location.pathname;
                        } else {
                            $window.location.hash = '';
                        }

                        if (requestInfo.requestType !== _adal.REQUEST_TYPE.LOGIN) {
                            _adal.callback = $window.parent.AuthenticationContext().callback;
                            if (requestInfo.requestType === _adal.REQUEST_TYPE.RENEW_TOKEN) {
                                _adal.callback = $window.parent.callBackMappedToRenewStates[requestInfo.stateResponse];
                            }
                        }

                        // Return to callback if it is send from iframe
                        if (requestInfo.stateMatch) {
                            if (typeof _adal.callback === 'function') {
                                // Call within the same context without full page redirect keeps the callback
                                if (requestInfo.requestType === _adal.REQUEST_TYPE.RENEW_TOKEN) {
                                    // Idtoken or Accestoken can be renewed
                                    if (requestInfo.parameters['access_token']) {
                                        _adal.callback(_adal._getItem(_adal.CONSTANTS.STORAGE.ERROR_DESCRIPTION), requestInfo.parameters['access_token']);
                                        return;
                                    } else if (requestInfo.parameters['id_token']) {
                                        _adal.callback(_adal._getItem(_adal.CONSTANTS.STORAGE.ERROR_DESCRIPTION), requestInfo.parameters['id_token']);
                                        return;
                                    }
                                }
                            } else {
                                // normal full login redirect happened on the page
                                updateDataFromCache(_adal.config.loginResource);
                                if (_oauthData.userName) {
                                    //IDtoken is added as token for the app
                                    $timeout(function () {
                                        updateDataFromCache(_adal.config.loginResource);
                                        $rootScope.userInfo = _oauthData;
                                        // redirect to login requested page
                                        var loginStartPage = _adal._getItem(_adal.CONSTANTS.STORAGE.START_PAGE);
                                        if (loginStartPage) {
                                            $location.path(loginStartPage);
                                        }
                                    }, 1);
                                    $rootScope.$broadcast('adal:loginSuccess');
                                } else {
                                    $rootScope.$broadcast('adal:loginFailure', _adal._getItem(_adal.CONSTANTS.STORAGE.ERROR_DESCRIPTION));
                                }
                            }
                        }
                    } else {
                        // No callback. App resumes after closing or moving to new page.
                        // Check token and username
                        updateDataFromCache(_adal.config.loginResource);
                        if (!_adal._renewActive && !_oauthData.isAuthenticated && _oauthData.userName) {
                            if (!_adal._getItem(_adal.CONSTANTS.STORAGE.FAILED_RENEW)) {
                                // Idtoken is expired or not present
                                _isRenewingToken = true;
                                _adal.acquireToken(_adal.config.loginResource, function (error, tokenOut) {
                                    if (error) {
                                        _isRenewingToken = false;
                                        $rootScope.$broadcast('adal:tokenRenewFailure', 'auto renew failure ' + error);
                                    } else {
                                        _isRenewingToken = false;
                                        if (tokenOut) {
                                            _oauthData.isAuthenticated = true;
                                            $rootScope.$broadcast('adal:tokenRenewSuccess', _adal.config.loginResource);
                                        }
                                    }
                                });
                            }
                        }
                    }

                    $timeout(function () {
                        updateDataFromCache(_adal.config.loginResource);
                        $rootScope.userInfo = _oauthData;
                    }, 1);
                };

                var isInIFrame = function () {
                    try {
                        return window.self !== window.top;
                    } catch (e) {
                        console && console.error('isInIFrame: Unexpected error:', e);
                        return true;
                    }
                }

                var loginHandler = function () {
                    _adal.info('Login event for:' + $location.$$path);
                    if (_adal.config && _adal.config.localLoginUrl) {
                        $location.path(_adal.config.localLoginUrl);
                    } else {
                        // directly start login flow
                        _adal._saveItem(_adal.CONSTANTS.STORAGE.START_PAGE, $location.$$path);
                        _adal.info('Start login at:' + window.location.href);
                        $rootScope.$broadcast('adal:loginRedirect');
                        _adal.login();
                    }
                };

                function isADLoginRequired(route, global) {
                    return global.requireADLogin ? route.requireADLogin !== false : !!route.requireADLogin;
                }

                var routeChangeHandler = function (e, nextRoute) {
                    if (nextRoute && nextRoute.$$route && isADLoginRequired(nextRoute.$$route, _adal.config)) {
                        if (!_oauthData.isAuthenticated && !isInIFrame() && !_isRenewingToken) {
                            _adal.info('Route change event for:' + $location.$$path);
                            loginHandler();
                        }
                    }
                };

                var stateChangeHandler = function (e, nextRoute) {
                    if (nextRoute && isADLoginRequired(nextRoute, _adal.config)) {
                        if (!_oauthData.isAuthenticated && !isInIFrame() && !_isRenewingToken) {
                            _adal.info('State change event for:' + $location.$$path);
                            loginHandler();
                        }
                    }
                };

                // Route change event tracking to receive fragment and also auto renew tokens
                $rootScope.$on('$routeChangeStart', routeChangeHandler);

                $rootScope.$on('$stateChangeStart', stateChangeHandler);

                $rootScope.$on('$locationChangeStart', locationChangeHandler);

                updateDataFromCache(_adal.config.loginResource);
                $rootScope.userInfo = _oauthData;

                return {
                    // public methods will be here that are accessible from Controller
                    config: _adal.config,
                    login: function () {
                        _adal.login();
                    },
                    loginInProgress: function () {
                        return _adal.loginInProgress();
                    },
                    logOut: function () {
                        _adal.logOut();
                        //call signout related method
                    },
                    getCachedToken: function (resource) {
                        return _adal.getCachedToken(resource);
                    },
                    userInfo: _oauthData,
                    acquireToken: function (resource) {
                        // automated token request call
                        var deferred = $q.defer();
                        _cachedTokens[resource]= _adal.getCachedToken(resource);
                        _adal.acquireToken(resource, function (error, tokenOut) {
                            if (error) {
                                _adal.error('Error when acquiring token for resource: ' + resource, error);
                                $rootScope.$broadcast('adal:tokenRenewFailure', 'auto renew failure ' + error);
                                deferred.reject(error);
                            } else {
                                deferred.resolve(tokenOut);
                                if (_cachedTokens[resource] !== tokenOut) {
                                    $rootScope.$broadcast('adal:tokenRenewSuccess', resource);
                                    _cachedTokens[resource] = tokenOut;
                                }
                            }
                        });

                        return deferred.promise;
                    },
                    getUser: function () {
                        var deferred = $q.defer();
                        _adal.getUser(function (error, user) {
                            if (error) {
                                _adal.error('Error when getting user', error);
                                deferred.reject(error);
                            } else {
                                deferred.resolve(user);
                            }
                        });

                        return deferred.promise;
                    },
                    getResourceForEndpoint: function (endpoint) {
                        return _adal.getResourceForEndpoint(endpoint);
                    },
                    clearCache: function () {
                        _adal.clearCache();
                    },
                    clearCacheForResource: function (resource) {
                        _adal.clearCacheForResource(resource);
                    },
                    info: function(message) {
                        _adal.info(message);
                    },
                    verbose: function(message) {
                        _adal.verbose(message);
                    }
                };
            }];
        });

        // Interceptor for http if needed
        AdalModule.factory('ProtectedResourceInterceptor', ['adalAuthenticationService', '$q', '$rootScope', function (authService, $q, $rootScope) {

            return {
                request: function (config) {
                    if (config) {

                        // This interceptor needs to load service, but dependeny definition causes circular reference error.
                        // Loading with injector is suggested at github. https://github.com/angular/angular.js/issues/2367

                        config.headers = config.headers || {};

                        var resource = authService.getResourceForEndpoint(config.url);
                        if (resource === null) {
                            return config;
                        }

                        var tokenStored = authService.getCachedToken(resource);
                        var isEndpoint = false;
                        if (tokenStored) {
                            authService.info('Token is avaliable for this url ' + config.url);
                            // check endpoint mapping if provided
                            config.headers.Authorization = 'Bearer ' + tokenStored;
                            return config;
                        } else {

                            if (authService.config) {
                                for (var endpointUrl in authService.config.endpoints) {
                                    if (config.url.indexOf(endpointUrl) > -1) {
                                        isEndpoint = true;
                                    }
                                }
                            }

                            // Cancel request if login is starting
                            if (authService.loginInProgress()) {
                                authService.info('login already start.');
                                return $q.reject();
                            } else if (authService.config && isEndpoint) {
                                // external endpoints
                                // delayed request to return after iframe completes
                                var delayedRequest = $q.defer();
                                authService.acquireToken(resource).then(function (token) {
                                    authService.verbose('Token is avaliable');
                                    config.headers.Authorization = 'Bearer ' + token;
                                    delayedRequest.resolve(config);
                            }, function (err) {
                                delayedRequest.reject(err);
                            });

                                return delayedRequest.promise;
                            }
                        }

                        return config;
                    }
                },
                responseError: function (rejection) {
                    authService.info('Getting error in the response');
                    if (rejection && rejection.status === 401) {
                        var resource = authService.getResourceForEndpoint(rejection.config.url);
                        authService.clearCacheForResource(resource);
                        $rootScope.$broadcast('adal:notAuthorized', rejection, resource);
                    }

                    return $q.reject(rejection);
                }
            };
        }]);
    } else {
        console.error('Angular.JS is not included');
    }
}());
<|endoftext|>


<commit_before>var API = exports.API = function(model) {
  this.model = model
}

API.prototype.request = function(/*method, obj, success */) {
  // retrieve arguments
  var args    = Array.prototype.slice.call(arguments)
    , method  = args.shift()
    , success = args.pop()
    , obj, view, key, id

  if (method === 'list') {
    view = args.shift()
    key  = args.shift()
  } else if (method === 'get') {
    id = args[0]
  } else {
    if (args.length === 2)
      id = args.shift()
    else
      id = args[0].id
    obj  = args.shift()
  }

  // build ajax request
  var params = {
    type:     method === 'list' ? 'get' : method,
    dataType: 'json',
    url:      '/_api/' + this.model._type.toLowerCase(),
    success:  function(data) {
      if (obj) {
        for (var key in obj.$errors)
          obj.emit('errors.changed.' + key)
        obj.$errors = {}
      }
      success(null, data)
    },
    error:    function(xhr)  {
      if (xhr.status === 400 && xhr.responseText) {
        var err = JSON.parse(xhr.responseText)
          , old = obj.$errors
        obj.$errors = {}
        if (typeof err.details === 'object') {
          Object.keys(err.details).forEach(function(key) {
            obj.$errors[key] = err.details[key]
            obj.emit('errors.changed.' + key)
          })
          obj.$errors = err.details
          for (var key in old) {
            if (!(key in obj.$errors))
              obj.emit('errors.changed.' + key)
          }
        }
        success({ status: xhr.status, message: xhr.statusText, details: err }, null)
      } else {
        success({ status: xhr.status, message: xhr.statusText }, null)
      }
    }
  }

  // compose url
  if (method === 'list') {
    if (view) {
      params.url += '?view=' + view
      if (key) params.url += '&key=' + key
    }
  }
  else if (method != 'post') {
    params.url += '/' + encodeURIComponent(id)
  }

  // add data
  if (method == 'post' || method == 'put') {
    params.contentType = 'application/json'
    params.data = JSON.stringify(obj instanceof this.model ? obj.toJSON() : obj)
  }

  // Fire in the hole
  $.ajax(params)
}

API.prototype.createModel = function(data) {
  var instance = new this.model(data)
  instance.isNew = false
  return instance
}

API.prototype.mergeModel = function(instance, data) {
  Object.keys(data).forEach(function(key) {
    if (instance.hasOwnProperty(key) && instance[key] !== data[key] && instance._changedValues[key] === undefined)
      instance[key] = data[key]
  })
}

API.prototype.get = function(id, callback) {
  var that = this
  this.request('get', id, function(err, data) {
    if (err) return callback(err, null)
    callback(null, data === null ? null : that.createModel(data))
  })
}

API.prototype.list = function(/* view, key, callback */) {
  var that = this
    , args = Array.prototype.slice.call(arguments)
    , callback = args.pop()
  this.request.apply(this, ['list'].concat(args, function(err, data) {
    if (err) return callback(err, null)
    if (!data || !Array.isArray(data)) return callback(null, data || null)
    callback(null, data.map(function(row) {
      return that.createModel(row)
    }))
  }))
}

API.prototype.put = function(/*instance, callback*/) {
  var args = Array.prototype.slice.call(arguments)
    , callback = args.pop()
    , that = this
  this.request.apply(this, ['put'].concat(args, function(err, data) {
    if (err) return callback(err, null)
    var instance = typeof args[0] === 'object' ? args[0] : args[1]
    that.mergeModel(instance, data)
    instance.isNew = false
    callback(null, instance)
  }))
}

API.prototype.post = function(instance, callback) {
  var that = this
  this.request('post', instance, function(err, data) {
    if (err) return callback(err, null)
    if (!(instance instanceof that.model))
      instance = that.createModel(instance)
    that.mergeModel(instance, data)
    instance.isNew = false
    callback(null, instance)
  })
}

API.prototype.delete = function(instance, callback) {
  var args = Array.prototype.slice.call(arguments)
    , callback = args.pop()
  this.request.apply(this, ['delete'].concat(args, function(err, data) {
    if (err) return callback(err, null)
    callback(null)
  }))
}

exports.initialize = function(model, opts, definition, callback) {
  var api = new API(model)
  callback()
  return api
}
<commit_msg>Implement Client-Side Data Caching<commit_after>var API = exports.API = function(model) {
  this.model = model
  this.cache = { views: {}, models: {} }
}

API.prototype.request = function(/*method, obj, success */) {
  // retrieve arguments
  var args    = Array.prototype.slice.call(arguments)
    , method  = args.shift()
    , success = args.pop()
    , obj, view, key, id

  if (method === 'list') {
    view = args.shift()
    key  = args.shift()
  } else if (method === 'get') {
    id = args[0]
  } else {
    if (args.length === 2)
      id = args.shift()
    else
      id = args[0].id
    obj  = args.shift()
  }

  // build ajax request
  var params = {
    type:     method === 'list' ? 'get' : method,
    dataType: 'json',
    url:      '/_api/' + this.model._type.toLowerCase(),
    success:  function(data) {
      if (obj) {
        for (var key in obj.$errors)
          obj.emit('errors.changed.' + key)
        obj.$errors = {}
      }
      success(null, data)
    },
    error:    function(xhr)  {
      if (xhr.status === 400 && xhr.responseText) {
        var err = JSON.parse(xhr.responseText)
          , old = obj.$errors
        obj.$errors = {}
        if (typeof err.details === 'object') {
          Object.keys(err.details).forEach(function(key) {
            obj.$errors[key] = err.details[key]
            obj.emit('errors.changed.' + key)
          })
          obj.$errors = err.details
          for (var key in old) {
            if (!(key in obj.$errors))
              obj.emit('errors.changed.' + key)
          }
        }
        success({ status: xhr.status, message: xhr.statusText, details: err }, null)
      } else {
        success({ status: xhr.status, message: xhr.statusText }, null)
      }
    }
  }

  // compose url
  if (method === 'list') {
    if (view) {
      params.url += '?view=' + view
      if (key) params.url += '&key=' + key
    }
  }
  else if (method != 'post') {
    params.url += '/' + encodeURIComponent(id)
  }

  // add data
  if (method == 'post' || method == 'put') {
    params.contentType = 'application/json'
    params.data = JSON.stringify(obj instanceof this.model ? obj.toJSON() : obj)
  }

  // Fire in the hole
  $.ajax(params)
}

API.prototype.createModel = function(data) {
  var instance = new this.model(data)
  instance.isNew = false
  return this.cache.models[instance.id] = instance
}

API.prototype.mergeModel = function(instance, data) {
  Object.keys(data).forEach(function(key) {
    if (instance.hasOwnProperty(key) && instance[key] !== data[key] && instance._changedValues[key] === undefined)
      instance[key] = data[key]
  })
}

API.prototype.get = function(id, callback) {
  var that = this
  if (id in this.cache.models) return callback(null, this.cache.models[id])
  this.request('get', id, function(err, data) {
    if (err) return callback(err, null)
    callback(null, that.cache.models[id] = (data === null ? null : that.createModel(data)))
  })
}

API.prototype.list = function(/* view, key, callback */) {
  var that = this
    , args = Array.prototype.slice.call(arguments)
    , callback = args.pop()
    , id = args.join('/')
  if (!that.cache.views[this.model._type]) that.cache.views[this.model._type] = {}
  if (id in this.cache.views[this.model._type]) {
    return callback(null, [].concat(this.cache.views[this.model._type][id]))
  }
  this.request.apply(this, ['list'].concat(args, function(err, data) {
    if (err) return callback(err, null)
    if (!data || !Array.isArray(data)) return callback(null, data || null)
    callback(null, that.cache.views[that.model._type][id] = data.map(function(row) {
      return that.createModel(row)
    }))
  }))
}

API.prototype.put = function(/*instance, callback*/) {
  var args = Array.prototype.slice.call(arguments)
    , callback = args.pop()
    , that = this
  this.request.apply(this, ['put'].concat(args, function(err, data) {
    if (err) return callback(err, null)
    var instance = typeof args[0] === 'object' ? args[0] : args[1]
    that.mergeModel(instance, data)
    instance.isNew = false
    callback(null, that.cache.models[instance.id] = instance)
  }))
}

API.prototype.post = function(instance, callback) {
  var that = this
  this.request('post', instance, function(err, data) {
    if (err) return callback(err, null)
    if (!(instance instanceof that.model))
      instance = that.createModel(instance)
    that.mergeModel(instance, data)
    instance.isNew = false
    that.cache.views[that.model._type] = {}
    callback(null, that.cache.models[instance.id] = instance)
  })
}

API.prototype.delete = function(instance, callback) {
  var args = Array.prototype.slice.call(arguments)
    , callback = args.pop(), that = this
  this.request.apply(this, ['delete'].concat(args, function(err, data) {
    if (err) return callback(err, null)
    that.cache.models[instance.id] = null
    that.cache.views[that.model._type] = {}
    callback(null)
  }))
}

exports.initialize = function(model, opts, definition, callback) {
  var api = new API(model)
  callback()
  return api
}
<|endoftext|>