Ejemplo n.º 1
0
exports.isString = function (value, name) {
    /// <summary>
    /// Ensure the value is a string.
    /// </summary>
    /// <param name="value" mayBeNull="true">The value to check.</param>
    /// <param name="name" mayBeNull="true" optional="true" type="String">
    /// Optional name of the value to throw.
    /// </param>

    if (!_.isString(value)) {
        throw _.format(
            Platform.getResourceString("Validate_TypeCheckError"),
            name || 'Value',
            'string',
            typeof value);
    }
};
function onLoginComplete(error, token, client, callback) {
    /// <summary>
    /// Handles the completion of the login and calls the user's callback with
    /// either a user or an error.
    /// </summary>
    /// <param name="error" type="string" mayBeNull="true">
    /// Optional error that may have occurred during login. Will be null if the
    /// login succeeded and their is a token.
    /// </param>
    /// <param name="token" type="string" mayBeNull="true">
    /// Optional token that represents the logged-in user. Will be null if the
    /// login failed and their is an error.
    /// </param>
    /// <param name="client" type="MobileServiceClient">
    /// The Mobile Service client associated with the login.
    /// </param>
    /// <param name="callback" type="Function" mayBeNull="true">
    /// The callback to execute when the login completes: callback(error, user).
    /// </param>
    var user = null;

    if (_.isNull(error)) {

        // Validate the token
        if (_.isNull(token) ||
            !_.isObject(token) ||
            !_.isObject(token.user) ||
            !_.isString(token.authenticationToken)) {
            error = Platform.getResourceString("MobileServiceLogin_InvalidResponseFormat");
        }
        else {
            // Set the current user on the client and return it in the callback
            client.currentUser = token.user;
            client.currentUser.mobileServiceAuthenticationToken = token.authenticationToken;
            user = client.currentUser;
        }
    }

    if (!_.isNull(callback)) {
        callback(error, user);
    }
}
MobileServiceLogin.prototype.login = function (provider, token, useSingleSignOn, callback) {
    /// <summary>
    /// Log a user into a Mobile Services application given a provider name and optional token object
    /// Microsoft Account authentication token.
    /// </summary>
    /// <param name="provider" type="String" mayBeNull="true">
    /// Optional name of the authentication provider to use; one of 'facebook', 'twitter', 'google', or 'microsoftaccount'.
    /// </param>
    /// <param name="token" type="Object"  mayBeNull="true">
    /// Optional provider specific object with existing OAuth token to log in with or
    /// a JWT Mobile Services authentication token if the provider is null.
    /// </param>
    /// <param name="useSingleSignOn" type="Boolean" mayBeNull="true">
    /// Only applies to Windows 8 clients.  Will be ignored on other platforms.
    /// Indicates if single sign-on should be used. Single sign-on requires that the 
    /// application's Package SID be registered with the Windows Azure Mobile Service, 
    /// but it provides a better experience as HTTP cookies are supported so that users 
    /// do not have to login in everytime the application is launched.
    /// </param>
    /// <param name="callback" type="Function"  mayBeNull="true">
    /// Optional callback accepting (error, user) parameters.
    /// </param>

    // Account for absent optional arguments
    if (_.isNull(callback)) {
        if (!_.isNull(useSingleSignOn) && (typeof useSingleSignOn === 'function')) {
            callback = useSingleSignOn;
            useSingleSignOn = null;
        }
        else if (!_.isNull(token) && (typeof token === 'function')) {
            callback = token;
            useSingleSignOn = null;
            token = null;
        }
    }
    if (_.isNull(useSingleSignOn)) {
        if (_.isBool(token)) {
            useSingleSignOn = token;
            token = null;
        }
        else {
            useSingleSignOn = false;
        }
    }
    
    // Determine if the provider is actually a Mobile Services authentication token
    if (_.isNull(token) && _.isString(provider) && provider.split('.').length === 3) {
        token = provider;
        provider = null;
    }

    // Validate parameters; there must be either a provider, a token or both
    if (_.isNull(provider)) {
        Validate.notNull(token);
        Validate.isString(token);
    }
    if (_.isNull(token)) {
        Validate.notNull(provider);
        Validate.isString(provider);
        provider = provider.toLowerCase();
    }

    if (!_.isNull(provider)) {
        this.loginWithProvider(provider, token, useSingleSignOn, callback);
    }
    else {
        this.loginWithMobileServiceToken(token, callback);
    }
};
MobileServiceTable.prototype._read = function (query, parameters, callback) {
    /// <summary>
    /// Query a table.
    /// </summary>
    /// <param name="query" type="Object" mayBeNull="true">
    /// The query to execute.  It can be null or undefined to get the entire
    /// collection.
    /// </param>
    /// <param name="parameters" type="Object" mayBeNull="true">
    /// An object of user-defined parameters and values to include in the request URI query string.
    /// </param>
    /// <param name="callback" type="Function">
    /// The callback to invoke when the query is complete.
    /// </param>

    // Account for absent optional arguments
    if (_.isNull(callback))
    {
        if (_.isNull(parameters) && (typeof query === 'function')) {
            callback = query;
            query = null;
            parameters = null;
        } else if (typeof parameters === 'function') {
            callback = parameters;
            parameters = null;
            if (!_.isNull(query) && _.isObject(query)) {
                // This 'query' argument could be either the query or the user-defined 
                // parameters object since both are optional.  A query is either (a) a simple string 
                // or (b) an Object with an toOData member. A user-defined parameters object is just 
                // an Object.  We need to detect which of these has been passed in here.
                if (!_.isString(query) && _.isNull(query.toOData)) {
                    parameters = query;
                    query = null;
                }
            }
        }
    }

    // Validate the arguments
    if (query && _.isString(query)) {
        Validate.notNullOrEmpty(query, 'query');
    }
    if (!_.isNull(parameters)) {
        Validate.isValidParametersObject(parameters, 'parameters');
    }
    Validate.notNull(callback, 'callback');

    // Get the query string
    var tableName = this.getTableName();
    var queryString = null;
    var projection = null;
    if (_.isString(query)) {
        queryString = query;
    } else if (_.isObject(query) && !_.isNull(query.toOData)) {
        if (query.getComponents) {
            var components = query.getComponents();
            projection = components.projection;
            if (components.table) {
                // If the query has a table name, make sure it's compatible with
                // the table executing the query
                
                if (tableName !== components.table) {
                    var message = _.format(Platform.getResourceString("MobileServiceTable_ReadMismatchedQueryTables"), tableName, components.table);
                    callback(_.createError(message), null);
                    return;
                }

                // The oDataQuery will include the table name; we need to remove
                // because the url fragment already includes the table name.
                var oDataQuery = query.toOData();
                queryString = oDataQuery.replace(new RegExp('^/' + components.table), '');
            }
        }
    }

    // Add any user-defined query string parameters
    if (!_.isNull(parameters)) {
        var userDefinedQueryString = _.url.getQueryString(parameters);
        if (!_.isNullOrEmpty(queryString)) {
            queryString += '&' + userDefinedQueryString;
        }
        else {
            queryString = userDefinedQueryString;
        }
    }
    
    // Construct the URL
    var urlFragment = _.url.combinePathSegments(tableRouteSeperatorName, tableName);
    if (!_.isNull(queryString)) {
        urlFragment = _.url.combinePathAndQuery(urlFragment, queryString);
    }

    // Make the request
    this.getMobileServiceClient()._request(
        'GET',
        urlFragment,
        null,
        function (error, response) {
            var values = null;
            if (_.isNull(error)) {
                // Parse the response
                values = _.fromJson(response.responseText);

                // If the values include the total count, we'll attach that
                // directly to the array
                if (values &&
                    !Array.isArray(values) &&
                    typeof values.count !== 'undefined' &&
                    typeof values.results !== 'undefined') {
                    // Create a new total count property on the values array
                    values.results.totalCount = values.count;
                    values = values.results;
                }

                // If we have a projection function, apply it to each item
                // in the collection
                if (projection !== null) {
                    var i = 0;
                    for (i = 0; i < values.length; i++) {
                        values[i] = projection.call(values[i]);
                    }
                }
            }
            callback(error, values);
        });
};
MobileServiceClient.prototype._request = function (method, uriFragment, content, ignoreFilters, headers, callback) {
    /// <summary>
    /// Perform a web request and include the standard Mobile Services headers.
    /// </summary>
    /// <param name="method" type="string">
    /// The HTTP method used to request the resource.
    /// </param>
    /// <param name="uriFragment" type="String">
    /// URI of the resource to request (relative to the Mobile Services
    /// runtime).
    /// </param>
    /// <param name="content" type="Object">
    /// Optional content to send to the resource.
    /// </param>
    /// <param name="ignoreFilters" type="Boolean" mayBeNull="true">
    /// Optional parameter to indicate if the client filters should be ignored
    /// and the request should be sent directly. Is false by default.
    /// </param>
    /// <param name="headers" type="Object">
    /// Optional request headers
    /// </param>
    /// <param name="callback" type="function(error, response)">
    /// Handler that will be called on the response.
    /// </param>

    // Account for absent optional arguments
    if (_.isNull(callback) && (typeof headers === 'function')) {
        callback = headers;
        headers = null;
    }

    if (_.isNull(callback) && (typeof ignoreFilters === 'function')) {
        callback = ignoreFilters;
        ignoreFilters = false;
    }

    Validate.isString(method, 'method');
    Validate.notNullOrEmpty(method, 'method');
    Validate.isString(uriFragment, 'uriFragment');
    Validate.notNull(uriFragment, 'uriFragment');
    Validate.notNull(callback, 'callback');

    // Create the absolute URI
    var options = { type: method.toUpperCase() };
    options.url = _.url.combinePathSegments(this.applicationUrl, uriFragment);

    // Set MobileServices authentication, application, User-Agent and telemetry headers
    options.headers = {};
    if (!_.isNull(headers)) {
        _.extend(options.headers, headers);
    }
    options.headers["X-ZUMO-INSTALLATION-ID"] = MobileServiceClient._applicationInstallationId;
    if (!_.isNullOrEmpty(this.applicationKey)) {
        options.headers["X-ZUMO-APPLICATION"] = this.applicationKey;
    }
    if (this.currentUser && !_.isNullOrEmpty(this.currentUser.mobileServiceAuthenticationToken)) {
        options.headers["X-ZUMO-AUTH"] = this.currentUser.mobileServiceAuthenticationToken;
    }
    if (!_.isNull(MobileServiceClient._userAgent)) {
        options.headers["User-Agent"] = MobileServiceClient._userAgent;
    }
    if (!_.isNullOrEmpty["X-ZUMO-VERSION"]) {
        options.headers["X-ZUMO-VERSION"] = this.version;
    }

    // Add any content as JSON
    if (!_.isNull(content)) {
        if (!_.isString(content)) {
            options.data = _.toJson(content);
        } else {
            options.data = content;
        }

        if(!_.hasProperty(options.headers, ['Content-Type','content-type','CONTENT-TYPE','Content-type'])) {
            options.headers['Content-Type'] = 'application/json';
        }
    } else {
        // options.data must be set to null if there is no content or the xhr object
        // will set the content-type to "application/text" for non-GET requests.
        options.data = null;
    }

    // Treat any >=400 status codes as errors.  Also treat the status code 0 as
    // an error (which indicates a connection failure).
    var handler = function (error, response) {
        if (!_.isNull(error)) {
            error = _.createError(error);
        } else if (!_.isNull(response) && (response.status >= 400 || response.status === 0)) {
            error = _.createError(null, response);
            response = null;
        }
        callback(error, response);
    };

    // Make the web request
    if (!_.isNull(this._serviceFilter) && !ignoreFilters) {
        this._serviceFilter(options, Platform.webRequest, handler);
    } else {
        Platform.webRequest(options, handler);
    }
};
    function (instance, parameters, callback) {
        /// <summary>
        /// Delete an object from a given table.
        /// </summary>
        /// <param name="instance" type="Object">
        /// The instance to delete from the table.
        /// </param>
        /// <param name="parameters" type="Object" mayBeNull="true">
        /// An object of user-defined parameters and values to include in the request URI query string.
        /// </param>
        /// <param name="callback" type="Function">
        /// The callback to invoke when the delete is complete.
        /// </param>

        // Account for absent optional arguments
        if (_.isNull(callback) && (typeof parameters === 'function')) {
            callback = parameters;
            parameters = null;
        }        

        // Validate the arguments
        Validate.notNull(instance, 'instance');
        Validate.isValidId(instance[idPropertyName], 'instance.' + idPropertyName);
        Validate.notNull(callback, 'callback');

        var headers = {};
        var features = [];
        if (_.isString(instance[idPropertyName])) {
            if (!_.isNullOrEmpty(instance.__version)) {
                headers['If-Match'] = getEtagFromVersion(instance.__version);
                features.push(WindowsAzure.MobileServiceClient._zumoFeatures.OptimisticConcurrency);
            }
        }

        features = addQueryParametersFeaturesIfApplicable(features, parameters);

        parameters = addSystemProperties(parameters, this.systemProperties);
        if (!_.isNull(parameters)) {
            Validate.isValidParametersObject(parameters);
        }

        // Contruct the URL
        var urlFragment =  _.url.combinePathSegments(
                tableRouteSeperatorName,
                this.getTableName(),
                encodeURIComponent(instance[idPropertyName].toString()));
        if (!_.isNull(parameters)) {
            var queryString = _.url.getQueryString(parameters);
            urlFragment = _.url.combinePathAndQuery(urlFragment, queryString);
        }

        // Make the request
        this.getMobileServiceClient()._request(
            'DELETE',
            urlFragment,
            null,
            false,
            headers,
            features,
            function (error, response) {
                if (!_.isNull(error)) {
                    setServerItemIfPreconditionFailed(error);
                }
                callback(error);
            });
    });
    function (instance, parameters, callback) {
        /// <summary>
        /// Insert a new object into a table.
        /// </summary>
        /// <param name="instance" type="Object">
        /// The instance to insert into the table.
        /// </param>
        /// <param name="parameters" type="Object" mayBeNull="true">
        /// An object of user-defined parameters and values to include in the request URI query string.
        /// </param>
        /// <param name="callback" type="Function">
        /// The callback to invoke when the insert is complete.
        /// </param>

        // Account for absent optional arguments
        if (_.isNull(callback) && (typeof parameters === 'function')) {
            callback = parameters;
            parameters = null;
        }

        // Validate the arguments
        Validate.notNull(instance, 'instance');
        if (!_.isNull(parameters)) {
            Validate.isValidParametersObject(parameters);
        }
        Validate.notNull(callback, 'callback');

        // Integer Ids can not have any Id set
        for (var i in idNames) {
            var id = instance[idNames[i]];

            if (!_.isNullOrZero(id)) {
                if (_.isString(id)) {
                    // String Id's are allowed iif using 'id'
                    if (idNames[i] !== idPropertyName) {
                        throw _.format(
                            Platform.getResourceString("MobileServiceTable_InsertIdAlreadySet"),
                            idPropertyName);
                    } else {
                        Validate.isValidId(id, idPropertyName);
                    }
                } else {
                    throw _.format(
                        Platform.getResourceString("MobileServiceTable_InsertIdAlreadySet"),
                        idPropertyName);
                }
            }
        }

        var features = addQueryParametersFeaturesIfApplicable([], parameters);

        // Construct the URL
        var urlFragment = _.url.combinePathSegments(tableRouteSeperatorName, this.getTableName());
        parameters = addSystemProperties(parameters, this.systemProperties);
        if (!_.isNull(parameters)) {
            var queryString = _.url.getQueryString(parameters);
            urlFragment = _.url.combinePathAndQuery(urlFragment, queryString);
        }

        // Make the request
        this.getMobileServiceClient()._request(
            'POST',
            urlFragment,
            instance,
            false,
            null,
            features,
            function (error, response) {
                if (!_.isNull(error)) {
                    callback(error, null);
                } else {
                    var result = getItemFromResponse(response);
                    result = Platform.allowPlatformToMutateOriginal(instance, result);
                    callback(null, result);
                }
            });
    });