示例#1
0
文件: dao.js 项目: funball99/Hilary
var hashToUser = function(hash) {
    // Ensure that the timezone we're setting is something the app can deal with.
    var timezone = hash.timezone;
    try {
        var date = new TZ.Date(null, timezone);
        if (!date.getTimezone()) {
            throw new Error();
        }
    } catch (err) {
        // We can't deal with this timezone.
        // default to UTC
        timezone = 'Etc/UTC';
    }

    var user = new User(hash.tenantAlias, hash.principalId, hash.displayName, {
        'visibility': hash.visibility,
        'email': hash.email,
        'locale': hash.locale,
        'timezone': timezone,
        'publicAlias': hash.publicAlias,
        'isGlobalAdmin': sanitize(hash['admin:global']).toBooleanStrict(),
        'isTenantAdmin': sanitize(hash['admin:tenant']).toBooleanStrict(),
        'smallPictureUri': hash.smallPictureUri,
        'mediumPictureUri': hash.mediumPictureUri,
        'largePictureUri': hash.largePictureUri,
        'notificationsUnread': OaeUtil.getNumberParam(hash.notificationsUnread),
        'notificationsLastRead': OaeUtil.getNumberParam(hash.notificationsLastRead)
    });
    var extra = getExtraData(user, hash);
    if (extra) {
        user.extra = extra;
    }
    return user;
};
示例#2
0
文件: dao.js 项目: madwill/Hilary
var _createUpdatedDiscussionFromStorageHash = function(discussion, hash) {
    return new Discussion(
        discussion.tenant,
        discussion.id,
        discussion.createdBy,
        hash.displayName || discussion.displayName,
        hash.description || discussion.description,
        hash.visibility || discussion.visibility,
        OaeUtil.getNumberParam(discussion.created),
        OaeUtil.getNumberParam(hash.lastModified || discussion.lastModified)
    );
};
示例#3
0
文件: dao.js 项目: madwill/Hilary
var _storageHashToDiscussion = function(discussionId, hash) {
    return new Discussion(
        TenantsAPI.getTenant(hash.tenantAlias),
        discussionId,
        hash.createdBy,
        hash.displayName,
        hash.description,
        hash.visibility,
        OaeUtil.getNumberParam(hash.created),
        OaeUtil.getNumberParam(hash.lastModified)
    );
};
示例#4
0
文件: api.js 项目: oaeproject/Hilary
const searchTenants = function(q, opts) {
  q = _.isString(q) ? q.trim() : null;
  opts = opts || {};
  opts.start = OaeUtil.getNumberParam(opts.start, 0);

  // Determine if we should included disabled/deleted tenants
  const includeDisabled = _.isBoolean(opts.disabled) ? opts.disabled : false;

  // Create a sorted result of tenants based on the user's query. If there was no query, we will
  // pull the pre-sorted list of tenants from the global cache
  let results = null;
  if (q) {
    results = _.chain(tenantSearchIndex.search(q))
      .sortBy('ref')
      .sortBy('score')
      .pluck('ref')
      .map(getTenant)
      .value();
  } else {
    results = tenantsSorted;
  }

  results = _.filter(results, result => {
    if (result.isGlobalAdminServer) {
      return false;
    }

    if (!includeDisabled) {
      return result.active && !result.deleted;
    }

    return true;
  });

  // Keep track of how many results we had in total
  const total = _.size(results);

  // Determine the end of our page slice
  opts.limit = OaeUtil.getNumberParam(opts.limit, total);
  const end = opts.start + opts.limit;

  // Cut down to just the requested page, and clone the tenants to avoid tenants being updated
  // in the cache
  results = results.slice(opts.start, end);
  results = _.map(results, _copyTenant);

  return {
    total,
    results
  };
};
示例#5
0
var _createUpdatedMeetingFromStorageHash = function(meeting, hash) {
    return new Meeting(
        meeting.tenant,
        meeting.id,
        meeting.createdBy,
        hash.displayName || meeting.displayName,
        hash.description || meeting.description,
        hash.record || meeting.record,
        hash.allModerators || meeting.allModerators,
        hash.waitModerator || meeting.waitModerator,
        hash.visibility || meeting.visibility,
        OaeUtil.getNumberParam(meeting.created),
        OaeUtil.getNumberParam(hash.lastModified || meeting.lastModified)
    );
};
示例#6
0
var _storageHashToMeeting = function(meetingId, hash) {
    return new Meeting(
        TenantsAPI.getTenant(hash.tenantAlias),
        meetingId,
        hash.createdBy,
        hash.displayName,
        hash.description,
        hash.record,
        hash.allModerators,
        hash.waitModerator,
        hash.visibility,
        OaeUtil.getNumberParam(hash.created),
        OaeUtil.getNumberParam(hash.lastModified)
    );
};
示例#7
0
    var searchCallback = function(ctx, opts, callback) {
        // Sanitize the custom search options
        opts = opts || {};
        opts.principalId = opts.pathParams[0];
        opts.limit = OaeUtil.getNumberParam(opts.limit, 12, 1, 25);

        var validator = new Validator();
        validator.check(opts.principalId, {'code': 400, 'msg': 'Must specificy an id of a user or group to search'}).notEmpty();
        if (validator.hasErrors()) {
            return callback(validator.getFirstError());
        }

        var authzPrincipal = AuthzUtil.getPrincipalFromId(opts.principalId);
        if (ctx.user() && (ctx.user().isAdmin(authzPrincipal.tenantAlias) || ctx.user().id === opts.principalId)) {
            // Perform the search with full access when the current user is an administrator of (or *is*) the target principal
            _search(ctx, resourceType, true, opts, callback);
        } else if (ctx.user() && PrincipalsUtil.isGroup(opts.principalId)) {
            // If we're searching a group library, assume full access to all resources in the group if the user is a member of the group
            AuthzAPI.hasAnyRole(ctx.user().id, opts.principalId, function(err, hasAnyRole) {
                if (err) {
                    return callback(err);
                }
                _search(ctx, resourceType, hasAnyRole, opts, callback);
            });
        } else {
            // Either we're anonymous or we're searching some other user's library
            _search(ctx, resourceType, false, opts, callback);
        }
    };
示例#8
0
var getActivityStream = module.exports.getActivityStream = function(ctx, resourceId, activtyStreamType, start, limit, transformerType, callback) {
    var activityStream = getRegisteredActivityStreamType(activtyStreamType);
    transformerType = transformerType || ActivityConstants.transformerTypes.ACTIVITYSTREAMS;

    var validator = new Validator();
    validator.check(null, {'code': 401, 'msg': 'Must be logged in to see an activity stream'}).isLoggedInUser(ctx);
    validator.check(activtyStreamType, {'code': 400, 'msg': 'Must specify an activity stream'}).notEmpty();
    validator.check(resourceId, {'code': 400, 'msg': 'You can only view activity streams for a principal'}).isPrincipalId();
    validator.check(null, {'code': 400, 'msg': 'Unknown activity stream id'}).isObject(activityStream);
    validator.check(transformerType, {'code': 400, 'msg': 'Unknown activity transformer type'}).isIn(_.values(ActivityConstants.transformerTypes));
    if (validator.hasErrors()) {
        return callback(validator.getFirstError());
    }

    limit = OaeUtil.getNumberParam(limit, 25, 1);

    // Ensure the current user has access to this stream
    var authorizationHandler = activityStream.authorizationHandler || function(ctx, activtyStreamType, token, callback) { return callback(); };
    authorizationHandler(ctx, resourceId, null, function(err) {
        if (err) {
            return callback(err);
        }

        return _getActivityStream(ctx, resourceId + '#' + activtyStreamType, start, limit, transformerType, callback);
    });
};
示例#9
0
文件: dao.js 项目: JawadHF/Hilary
var getQueuedActivities = module.exports.getQueuedActivities = function(bucketNumber, limit, callback) {
    limit = OaeUtil.getNumberParam(limit, ActivitySystemConfig.getConfig().collectionBatchSize);

    // Get the first `limit` routed activities from the bucket. Since they are stored in a sorted list in Redis, we use the
    // "zrange" command. The "z" prefix to the command indicates that it is a sorted-list operation.
    redisClient.zrange(_createBucketCacheKey(bucketNumber), 0, limit, function(err, routedActivities) {
        if (err) {
            return callback(err);
        }

        // The Redis result is each value on a new line, in order of "rank" in the sorted-list. Iterate over those and parse the values in order.
        var queuedActivities = {};
        _.each(routedActivities, function(routedActivity) {
            try {
                // Routed activities are stored as stringified JSON, so we parse them back to objects
                routedActivity = JSON.parse(routedActivity);
            } catch (err) {
                log().warn({'err': err, 'routedActivity': routedActivity}, 'Error trying to parse stored routed activity.');
                return;
            }

            queuedActivities[_createRoutedActivityKey(routedActivity)] = routedActivity;
        });

        log().trace({'queuedActivities': queuedActivities}, 'Fetched queued activities.');

        return callback(null, queuedActivities);
    });
};
示例#10
0
文件: util.js 项目: madwill/Hilary
var createTestServer = module.exports.createTestServer = function(callback, _attempts) {
    _attempts = OaeUtil.getNumberParam(_attempts, 0);
    if (_attempts === 10) {
        assert.fail('Could not start a test web server in 10 attempts');
    }

    var port = 2500 + Math.floor(Math.random() * 1000);
    var app = express();

    app.use(bodyParser.urlencoded({'extended': true}));
    app.use(bodyParser.json());
    app.use(multipart());

    // Try and listen on the specified port
    var server = app.listen(port + _attempts);

    // When the server successfully begins listening, invoke the callback
    server.once('listening', function() {
        server.removeAllListeners('error');
        return callback(app, server, port + _attempts);
    });

    // If there is an error connecting, try another port
    server.once('error', function(err) {
        server.removeAllListeners('listening');
        return createTestServer(callback, _attempts + 1);
    });
};
示例#11
0
文件: email.js 项目: mrvisser/Hilary
module.exports = function(ctx, opts, callback) {
    // Sanitize custom search options
    opts = opts || {};
    opts.limit = OaeUtil.getNumberParam(opts.limit, 10, 1, 25);

    var validator = new Validator();
    validator.check(null, {'code': 401, 'msg': 'Only authenticated users can use email search'}).isLoggedInUser(ctx);
    validator.check(opts.q, {'code': 400, 'msg': 'An invalid email address has been specified'}).isEmail();
    if (validator.hasErrors()) {
        return callback(validator.getFirstError());
    }

    // Ensure the email address being searched is lower case so it is case insensitive
    var email = opts.q.toLowerCase();

    var filterResources = SearchUtil.filterResources(['user']);
    var filterInteractingTenants = SearchUtil.filterInteractingTenants(ctx.user().tenant.alias);

    // When searching for users by email, we can ignore profile visibility in lieu of an email
    // exact match. The user profile is still "scrubbed" of private information on its way out,
    // however we enable the ability for a user to share with that profile if they know the email
    // address
    var query = SearchUtil.createEmailQuery(email);
    var queryOpts = _.extend({}, opts, {'minScore': 0});
    var filter = SearchUtil.filterAnd(filterResources, filterInteractingTenants);
    return callback(null, SearchUtil.createQuery(query, filter, queryOpts));
};
示例#12
0
var getMembershipsLibrary = module.exports.getMembershipsLibrary = function(ctx, principalId, start, limit, callback) {
    limit = OaeUtil.getNumberParam(limit, 10, 1);

    var validator = new Validator();
    validator.check(principalId, {'code': 400, 'msg': 'Must specify a valid principalId'}).isPrincipalId();
    if (validator.hasErrors()) {
        return callback(validator.getFirstError());
    }

    PrincipalsDAO.getPrincipal(principalId, function(err, principal) {
        if (err) {
            return callback(err);
        } else if (principal.deleted) {
            return callback({'code': 404, 'msg': util.format('Couldn\'t find principal: %s', principalId)});
        }

        LibraryAPI.Authz.resolveTargetLibraryAccess(ctx, principal.id, principal, function(err, hasAccess, visibility) {
            if (err) {
                return callback(err);
            } else if (!hasAccess) {
                return callback({'code': 401, 'msg': 'You do not have access to this memberships library'});
            }

            return _getMembershipsLibrary(ctx, principalId, visibility, start, limit, callback);
        });
    });
};
示例#13
0
文件: util.js 项目: udayg/Hilary
    RestAPI.Activity.markNotificationsRead(restContext, function(err, _result) {
        assert.ok(!err);

        // Assert we're getting back a number
        result = _result;
        var lastReadTime = _result.lastReadTime;
        assert.strictEqual(lastReadTime, OaeUtil.getNumberParam(lastReadTime));
    });
示例#14
0
var _storageHashToDiscussion = function(discussionId, hash) {

    // Use tenantAlias as a slug column to determine if this discussion actually existed
    if (!hash.tenantAlias) {
        return null;
    }

    return new Discussion(
        TenantsAPI.getTenant(hash.tenantAlias),
        discussionId,
        hash.createdBy,
        hash.displayName,
        hash.description,
        hash.visibility,
        OaeUtil.getNumberParam(hash.created),
        OaeUtil.getNumberParam(hash.lastModified)
    );
};
示例#15
0
文件: rest.js 项目: cyu019x/Hilary
OAE.tenantRouter.on('get', '/api/discussion/library/:principalId', function(req, res) {
    var limit = Util.getNumberParam(req.query.limit, 12, 1, 25);
    DiscussionsAPI.Discussions.getDiscussionsLibrary(req.ctx, req.params.principalId, req.query.start, limit, function(err, discussions, nextToken) {
        if (err) {
            return res.send(err.code, err.msg);
        }

        res.send(200, {'results': discussions, 'nextToken': nextToken});
    });
});
示例#16
0
文件: rest.js 项目: cyu019x/Hilary
OAE.tenantRouter.on('get', '/api/discussion/:discussionId/messages', function(req, res) {
    var limit = Util.getNumberParam(req.query.limit, 10, 1, 25);
    DiscussionsAPI.Discussions.getMessages(req.ctx, req.params.discussionId, req.query.start, limit, function(err, messages, nextToken) {
        if (err) {
            return res.send(err.code, err.msg);
        }

        res.send(200, {'results': messages, 'nextToken': nextToken});
    });
});
示例#17
0
var _hashToUser = function(hash) {
    var user = new User(hash.tenantAlias, hash.principalId, hash.displayName, hash.email, {
        'visibility': hash.visibility,
        'deleted': hash.deleted,
        'locale': hash.locale,
        'publicAlias': hash.publicAlias,
        'isGlobalAdmin': sanitize(hash['admin:global']).toBooleanStrict(),
        'isTenantAdmin': sanitize(hash['admin:tenant']).toBooleanStrict(),
        'smallPictureUri': hash.smallPictureUri,
        'mediumPictureUri': hash.mediumPictureUri,
        'largePictureUri': hash.largePictureUri,
        'notificationsUnread': OaeUtil.getNumberParam(hash.notificationsUnread),
        'notificationsLastRead': OaeUtil.getNumberParam(hash.notificationsLastRead),
        'emailPreference': hash.emailPreference || PrincipalsConfig.getValue(hash.tenantAlias, 'user', 'emailPreference'),
        'acceptedTC': OaeUtil.getNumberParam(hash.acceptedTC, 0),
        'lastModified': OaeUtil.getNumberParam(hash.lastModified)
    });
    return user;
};
示例#18
0
文件: rest.js 项目: davidoae/Hilary
OAE.tenantRouter.on('get', '/api/following/:userId/following', function(req, res) {
    var limit = OaeUtil.getNumberParam(req.query.limit, 10, 1, 25);
    FollowingAPI.getFollowing(req.ctx, req.params.userId, req.query.start, limit, function(err, following, nextToken) {
        if (err) {
            return res.status(err.code).send(err.msg);
        }

        return res.status(200).send({'results': following, 'nextToken': nextToken});
    });
});
module.exports = function(ctx, opts, callback) {
    // Sanitize custom search options
    opts = opts || {};
    opts.includeIndirect = (opts.includeIndirect !== 'false');
    opts.limit = OaeUtil.getNumberParam(opts.limit, 10, 1, 25);
    opts.q = SearchUtil.getQueryParam(opts.q);
    opts.resourceTypes = _getResourceTypesParam(opts.resourceTypes);
    opts.searchAllResourceTypes = (_.isEmpty(opts.resourceTypes));

    return _search(ctx, opts, callback);
};
示例#20
0
文件: rest.js 项目: Coenego/Hilary
OAE.tenantServer.get('/api/notifications', function(req, res) {
    req.telemetryUrl = '/api/notifications';
    var limit = OaeUtil.getNumberParam(req.query.limit, 10, 1, 25);
    ActivityAPI.getNotificationStream(req.ctx, req.query.start, limit, function(err, notificationStream) {
        if (err) {
            return res.send(err.code, err.msg);
        }

        res.send(200, notificationStream);
    });
});
示例#21
0
文件: util.js 项目: Julka7/Hilary
var createQuery = module.exports.createQuery = function(query, filter, opts) {
    opts = opts || {};

    var validator = new Validator();
    validator.check(null, new Error('createQuery expects a query object.')).isObject(query);
    if (validator.hasErrors()) {
        log().error({'err': validator.getFirstError()}, 'Invalid input provided to SearchUtil.createQuery');
        throw validator.getFirstError();
    }

    var data = null;
    if (filter) {
        // If we have filters, we need to create a 'filtered' query
        data = {
            'query': {
                'filtered': {
                    'query': query,
                    'filter': filter
                }
            }
        };
    } else {
        // If it's just a query, we wrap it in a standard query.
        data = {
            'query': query
        };
    }

    // Strip the opts down to the relevant ElasticSearch parameters
    opts = {
        'from': OaeUtil.getNumberParam(opts.start),
        'size': OaeUtil.getNumberParam(opts.limit),
        'sort': [
            {'_score': {'order': 'desc'}},
            {'sort': getSortParam(opts.sort)}
        ],
        'min_score': (_.isNumber(opts.minScore)) ? opts.minScore : SearchConstants.query.MINIMUM_SCORE
    };

    return _.extend(data, opts);
};
示例#22
0
文件: rest.js 项目: Coenego/Hilary
var _handleGetActivities = function(activityStreamId, req, res) {
    req.telemetryUrl = '/api/activity/activityStreamId';
    var limit = OaeUtil.getNumberParam(req.query.limit, 10, 1, 25);
    var start = req.query.start;
    ActivityAPI.getActivityStream(req.ctx, activityStreamId, start, limit, function(err, activityStream) {
        if (err) {
            return res.send(err.code, err.msg);
        }

        res.send(200, activityStream);
    });
};
示例#23
0
const init = function(_config, callback) {
  _config = _config || {};

  screenShottingOptions.timeout = OaeUtil.getNumberParam(_config.screenShotting.timeout, screenShottingOptions.timeout);

  const chromiumExecutable = _config.screenShotting.binary;
  if (chromiumExecutable) {
    screenShottingOptions.executablePath = chromiumExecutable;
  }

  return callback();
};
示例#24
0
文件: dao.js 项目: davidoae/Hilary
var getActivities = module.exports.getActivities = function(activityStreamId, start, limit, callback) {
    start = start || '';
    limit = OaeUtil.getNumberParam(limit, 25, 1);

    // Selecting with consistency ONE as having great consistency is not critical for activities
    Cassandra.runPagedQuery('ActivityStreams', 'activityStreamId', activityStreamId, 'activityId', start, limit, {'reversed': true}, function(err, rows, nextToken) {
        if (err) {
            return callback(err);
        }

        var activities = _rowsToActivities(rows);
        return callback(null, activities, nextToken);
    });
};
示例#25
0
文件: util.js 项目: JawadHF/Hilary
var generateRandomText = module.exports.generateRandomText = function(nrOfWords) {
    nrOfWords = OaeUtil.getNumberParam(nrOfWords, 1, 1);
    var alphabet = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    var text = [];
    for (var i = 0; i < nrOfWords; i++) {
        var wordLength = 12;
        var word = '';
        for (var l = 0; l < wordLength; l++) {
            var letter = Math.floor(Math.random() * alphabet.length);
            word += alphabet[letter];
        }
        text.push(word);
    }
    return text.join(' ');
};
示例#26
0
module.exports = function(ctx, opts, callback) {
    // Sanitize custom search options
    opts = opts || {};
    opts.resourceTypes = opts.resourceTypes || [];
    opts.includeExternal = (opts.includeExternal === 'true');
    opts.includeIndirect = (opts.includeIndirect !== 'false');
    opts.limit = OaeUtil.getNumberParam(opts.limit, 10, 1, 25);

    // Sanitize the resourceTypes array
    if (!_.isArray(opts.resourceTypes)) {
        // Convert to an array if it's a single value
        opts.resourceTypes = [opts.resourceTypes];
    }

    // Remove any falsy values from the array
    opts.resourceTypes = _.compact(opts.resourceTypes);

    // If there were no valid values for resource type, we search everything
    opts.searchAllResourceTypes = _.isEmpty(opts.resourceTypes);

    // opts.q is required to determine _needsFilterByAccess
    opts.q = SearchUtil.getQueryParam(opts.q);

    var needsFilterByAccess = _needsFilterByAccess(ctx, opts);
    if (needsFilterByAccess && opts.includeIndirect) {
        // We'll need to know the group membership of this user to scope by resources they have access to directly or indirectly
        AuthzAPI.getPrincipalMemberships(ctx.user().id, null, 10000, function(err, groups) {
            if (err) {
                return callback(err);
            }

            // Bind the access array to the search options
            var access = groups || [];
            access.push(ctx.user().id);
            opts.access = access;

            _search(ctx, opts, callback);
        });
    } else if (needsFilterByAccess && !opts.includeIndirect) {
        // If we're not including indirect resources, only filter by direct user access
        opts.access = [ctx.user().id];
        _search(ctx, opts, callback);
    } else {
        _search(ctx, opts, callback);
    }
};
示例#27
0
文件: dao.js 项目: JawadHF/Hilary
var getActivities = module.exports.getActivities = function(activityStreamId, start, limit, callback) {
    limit = OaeUtil.getNumberParam(limit, 25);

    // Selecting with consistency ONE as having great consistency is not critical for activities
    Cassandra.runPagedColumnQuery('ActivityStreams', 'activityStreamId', activityStreamId, start, limit, {'reversed': true, 'consistency': 'ONE'}, function(err, columns, nextToken) {
        if (err) {
            return callback(err);
        }

        var activities = _columnsToActivities(columns);

        /*
         * The following block of code is intended for migrating from 3.0.0 to 4.0.0 (Push)
         * The `activityStreamId` for "activity" activity streams is/was of the form: 
         *   -  4.0.0:   `u:cam:abc123#activity`   or    `g:cam:abc123#activity`
         *   -  3.0.0:   `u:cam:abc123`            or    `g:cam:abc123`
         *
         * If we detect that a user activity stream is being requested under the following circumstances,
         * we will try the old value as the `activityStreamId`.
         */
        
        // We only need to check with another activityStreamId if the "activity" stream is being requested. Notifications are unchanged
        var parsedActivityStreamId = ActivityUtil.parseActivityStreamId(activityStreamId);
        var isActivityStream = (parsedActivityStreamId.streamType === 'activity');
        if (!isActivityStream) {
            return callback(null, activities, nextToken);
        }

        // If we found the requested amount of activities we can return early
        if (activities.length === limit) {
            return callback(null, activities, nextToken);
        }

        // Otherwise we'll need to check the old value
        var oldActivityStreamLimit = limit - activities.length;
        Cassandra.runPagedColumnQuery('ActivityStreams', 'activityStreamId', parsedActivityStreamId.resourceId, start, oldActivityStreamLimit, {'reversed': true, 'consistency': 'ONE'}, function(err, columns, nextToken) {
            if (err) {
                return callback(err);
            }

            activities = activities.concat(_columnsToActivities(columns));
            return callback(null, activities, nextToken);
        });
    });
};
示例#28
0
文件: util.js 项目: madwill/Hilary
var generateTestUsers = module.exports.generateTestUsers = function(restCtx, total, callback, _createdUsers) {
    total = OaeUtil.getNumberParam(total, 1);
    _createdUsers = _createdUsers || [];
    if (total === 0) {
        var callbackArgs = [];
        callbackArgs.push(null);
        callbackArgs.push(_.indexBy(_createdUsers, function(user) { return user.user.id; }));
        callbackArgs = _.union(callbackArgs, _createdUsers);
        return callback.apply(callback, callbackArgs);
    }

    // Ensure that the provided rest context has been authenticated before trying to use it to
    // create users
    _ensureAuthenticated(restCtx, function(err) {
        if (err) {
            return callback(err);
        }

        var username = generateTestUserId('random-user');
        var displayName = generateTestGroupId('random-user');
        var email = generateTestEmailAddress(username);
        RestAPI.User.createUser(restCtx, username, 'password', displayName, {'email': email}, function(err, user) {
            if (err) {
                return callback(err);
            }

            _createdUsers.push({
                'user': user,
                'restContext': new RestContext(restCtx.host, {
                    'hostHeader': restCtx.hostHeader,
                    'username': username,
                    'userPassword': '******',
                    'strictSSL': restCtx.strictSSL
                })
            });

            // Recursively continue creating users
            return generateTestUsers(restCtx, --total, callback, _createdUsers);

        });
    });
};
示例#29
0
                                RestAPI.Activity.markNotificationsRead(simong.restContext, function(err, result) {
                                    var lastReadTime = result.lastReadTime;

                                    assert.strictEqual(lastReadTime, OaeUtil.getNumberParam(lastReadTime));

                                    // Verify the notificationsLastRead status
                                    RestAPI.User.getMe(simong.restContext, function(err, me) {
                                        assert.ok(!err);

                                        // We now have no unread notifications, and a lastRead status
                                        assert.strictEqual(me.notificationsUnread, 0);
                                        assert.strictEqual(me.notificationsLastRead, lastReadTime);

                                        // Create 2 content items again with simong as a member
                                        RestAPI.Content.createLink(mrvisser.restContext, 'Google', 'Google', 'private', 'http://www.google.ca', [], [simong.user.id], function(err, content) {
                                            assert.ok(!err);

                                            RestAPI.Content.createLink(mrvisser.restContext, 'Google', 'Google', 'private', 'http://www.google.ca', [], [simong.user.id], function(err, content) {
                                                assert.ok(!err);

                                                // Ensure the notification gets delivered and aggregated
                                                ActivityTestsUtil.collectAndGetNotificationStream(simong.restContext, null, function(err, notificationStream) {
                                                    assert.ok(!err);
                                                    assert.equal(notificationStream.items.length, 1);
                                                    assert.equal(notificationStream.items[0].actor['oae:id'], mrvisser.user.id);
                                                    assert.equal(notificationStream.items[0].object['oae:collection'].length, 3);

                                                    // Verify the notificationsUnread is incremented and notificationsLastRead status
                                                    RestAPI.User.getMe(simong.restContext, function(err, me) {
                                                        assert.ok(!err);

                                                        // We now have unread notifications, and a lastRead status
                                                        assert.strictEqual(me.notificationsUnread, 2);
                                                        assert.equal(me.notificationsLastRead, lastReadTime);

                                                        callback();
                                                    });
                                                });
                                            });
                                        });
                                    });
                                });
示例#30
0
var getMembersLibrary = module.exports.getMembersLibrary = function(ctx, groupId, start, limit, callback) {
    limit = OaeUtil.getNumberParam(limit, 10, 1);

    var validator = new Validator();
    validator.check(groupId, {'code': 400,'msg': 'An invalid group id was specified'}).isGroupId();
    if (validator.hasErrors()) {
        return callback(validator.getFirstError());
    }

    // Ensure that this group exists
    getGroup(ctx, groupId, function(err, group) {
        if (err) {
            return callback(err);
        } else if (group.deleted) {
            return callback({'code': 404, 'msg': util.format('Couldn\'t find principal: %s', groupId)});
        }

        // Get the members library to which the current user has access
        return _getMembersLibrary(ctx, group, null, start, limit, callback);
    });
};