You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@usergrid.apache.org by sn...@apache.org on 2014/01/28 00:21:58 UTC
[40/61] [abbrv] [partial] updated to latest Angular-based admin portal
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/508ef2f7/portal/js/global/ug-service.js
----------------------------------------------------------------------
diff --git a/portal/js/global/ug-service.js b/portal/js/global/ug-service.js
new file mode 100644
index 0000000..ba9d762
--- /dev/null
+++ b/portal/js/global/ug-service.js
@@ -0,0 +1,987 @@
+'use strict';
+
+AppServices.Services.factory('ug', function (configuration, $rootScope,utility) {
+
+ return {
+ get:function(prop,isObject){
+ return isObject ? this.client().getObject(prop) : this.client().get(prop);
+ },
+ set:function(prop,value){
+ this.client().set(prop,value);
+
+ },
+ orgLogin:function(username,password){
+ var self = this;
+ this.client().set('email', username);
+ this.client().set('token', null);
+ this.client().orgLogin(username,password,function(err, data, user, organizations, applications){
+ if(err){
+ $rootScope.$broadcast('loginFailed', err,data);
+ }else{
+ self.initializeCurrentUser(function () {
+ $rootScope.$broadcast('loginSuccesful', user, organizations, applications);
+ });
+ }
+ });
+ },
+
+ checkAuthentication:function(force){
+ var ug = this;
+ var client = ug.client();
+
+ var initialize = function () {
+ ug.initializeCurrentUser(function () {
+ $rootScope.userEmail = client.get('email');
+ $rootScope.organizations = client.getObject('organizations');
+ $rootScope.applications = client.getObject('applications');
+ $rootScope.currentOrg = client.get('orgName');
+ $rootScope.currentApp = client.get('appName');
+ var size = 0, key;
+ for (key in $rootScope.applications) {
+ if ($rootScope.applications.hasOwnProperty(key)) size++;
+ }
+ $rootScope.addApplications = size < 10;
+ $rootScope.$broadcast('checkAuthentication-success', client.getObject('organizations'), client.getObject('applications'), client.get('orgName'), client.get('appName'), client.get('email'));
+ });
+ },
+ isAuthenticated = function () {
+ var authenticated = client.get('token') !== null && client.get('organizations') !== null;
+ if (authenticated) {
+ initialize();
+ }
+ return authenticated;
+ };
+ if(!isAuthenticated() || force){
+ if(!client.get('token')){
+ return $rootScope.$broadcast('checkAuthentication-error','no token',{},client.get('email'));
+ }
+ this.client().reAuthenticateLite(function(err){
+ var missingData = err || ( !client.get('orgName') || !client.get('appName') || !client.getObject('organizations') || !client.getObject('applications'));
+ var email = client.get('email');
+ if(err || missingData){
+ $rootScope.$broadcast('checkAuthentication-error',err,missingData,email);
+ }else{
+ initialize();
+ }
+ });
+ }
+ },
+ reAuthenticate:function(email,eventOveride){
+ var ug = this;
+ this.client().reAuthenticate(email,function(err, data, user, organizations, applications){
+ if(!err){
+ $rootScope.currentUser = user;
+ }
+ if(!err){
+ $rootScope.userEmail = user.get('email');
+ $rootScope.organizations = organizations;
+ $rootScope.applications = applications;
+ $rootScope.currentOrg = ug.get('orgName');
+ $rootScope.currentApp = ug.get('appName');
+ $rootScope.currentUser = user._data;
+ $rootScope.currentUser.profileImg = utility.get_gravatar($rootScope.currentUser.email);
+ }
+ $rootScope.$broadcast((eventOveride || 'reAuthenticate')+'-' + (err ? 'error' : 'success'),err, data, user, organizations, applications);
+
+ });
+ },
+ logoutCallback: function() {
+ $rootScope.$broadcast('userNotAuthenticated');
+ },
+ logout:function(){
+ $rootScope.activeUI = false;
+ $rootScope.userEmail = 'user@apigee.com';
+ $rootScope.organizations = {"noOrg":{name:"No Orgs Found"}};
+ $rootScope.applications = {"noApp":{name:"No Apps Found"}};
+ $rootScope.currentOrg = 'No Org Found';
+ $rootScope.currentApp = 'No App Found';
+ sessionStorage.setItem('accessToken', null);
+ sessionStorage.setItem('userUUID', null);
+ sessionStorage.setItem('userEmail', null);
+
+ this.client().logout();
+ this._client = null;
+ },
+ client: function(){
+ var options = {
+ buildCurl:true,
+ logging:true
+ };
+ if(Usergrid.options && Usergrid.options.client){
+ options.keys = Usergrid.options.client;
+ }
+
+ this._client = this._client || new Usergrid.Client(options,
+ $rootScope.urls().DATA_URL
+ );
+ return this._client;
+ },
+ getTopCollections: function () {
+ var options = {
+ method:'GET',
+ endpoint: ''
+ }
+ this.client().request(options, function (err, data) {
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'error getting collections');
+ } else {
+ var collections = data.entities[0].metadata.collections;
+ $rootScope.$broadcast('top-collections-received', collections);
+ }
+ });
+ },
+ createCollection: function (collectionName) {
+ var collections = {};
+ collections[collectionName] = {};
+ var metadata = {
+ metadata: {
+ collections: collections
+ }
+ }
+ var options = {
+ method:'PUT',
+ body: metadata,
+ endpoint: ''
+ }
+ this.client().request(options, function (err, data) {
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'error creating collection');
+ } else {
+ $rootScope.$broadcast('collection-created', collections);
+ }
+ });
+ },
+ getApplications: function () {
+ this.client().getApplications(function (err, applications) {
+ if (err) {
+ applications && console.error(applications);
+ }else{
+ $rootScope.$broadcast('applications-received', applications);
+ }
+ });
+ },
+ getAdministrators: function () {
+ this.client().getAdministrators(function (err, administrators) {
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'error getting administrators');
+ }
+ $rootScope.$broadcast('administrators-received', administrators);
+ });
+ },
+ createApplication: function (appName) {
+ this.client().createApplication(appName, function (err, applications) {
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'error creating application');
+ }else{
+ $rootScope.$broadcast('applications-created', applications,appName);
+ $rootScope.$broadcast('applications-received', applications);
+ }
+ });
+ },
+ createAdministrator: function (adminName) {
+ this.client().createAdministrator(adminName, function (err, administrators) {
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'error creating administrator');
+ }
+ $rootScope.$broadcast('administrators-received', administrators);
+ });
+ },
+ getFeed: function () {
+ var options = {
+ method:'GET',
+ endpoint:'management/organizations/'+this.client().get('orgName')+'/feed',
+ mQuery:true
+ };
+ this.client().request(options, function (err, data) {
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'error getting feed');
+ } else {
+ var feedData = data.entities;
+ var feed = [];
+ var i=0;
+ for (i=0; i < feedData.length; i++) {
+ var date = (new Date(feedData[i].created)).toUTCString();
+
+ var title = feedData[i].title;
+
+ var n=title.indexOf(">");
+ title = title.substring(n+1,title.length);
+
+ n=title.indexOf(">");
+ title = title.substring(n+1,title.length);
+
+ if (feedData[i].actor) {
+ title = feedData[i].actor.displayName + ' ' + title;
+ }
+ feed.push({date:date, title:title});
+ }
+ if (i === 0) {
+ feed.push({date:"", title:"No Activities found."});
+ }
+
+ $rootScope.$broadcast('feed-received', feed);
+ }
+ });
+
+ },
+ createGroup: function (path, title) {
+ var options = {
+ path:path,
+ title:title
+ }
+ var self = this;
+ this.groupsCollection.addEntity(options, function(err){
+ if (err) {
+ $rootScope.$broadcast('groups-create-error', err);
+ } else {
+ $rootScope.$broadcast('groups-create-success', self.groupsCollection);
+ $rootScope.$broadcast('groups-received', self.groupsCollection);
+ }
+ });
+ },
+ createRole: function (name, title) {
+ var options = {
+ name:name,
+ title:title
+ },
+ self = this;
+ this.rolesCollection.addEntity(options, function(err){
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'error creating role');
+ } else {
+ $rootScope.$broadcast('roles-received', self.rolesCollection);
+ }
+ });
+ },
+ createUser: function (username, name, email, password){
+ var options = {
+ username:username,
+ name:name,
+ email:email,
+ password:password
+ }
+ var self = this;
+ this.usersCollection.addEntity(options, function(err, data){
+ if (err) {
+ if (data) {
+ $rootScope.$broadcast("alert", "error", "error: " + data);
+ } else {
+ $rootScope.$broadcast("alert", "error", "error creating user");
+ }
+ } else {
+ $rootScope.$broadcast('users-create-success', self.usersCollection);
+
+ $rootScope.$broadcast('users-received', self.usersCollection);
+ }
+ });
+ },
+ getCollection: function (type, path, orderBy, query, limit) {
+ var options = {
+ type:path,
+ qs:{}
+ }
+ if (query) {
+ options.qs['ql'] = query;
+ }
+
+ //force order by 'created desc' if none exists
+ if (options.qs.ql) {
+ options.qs['ql'] = options.qs.ql + ' order by ' + (orderBy || 'created desc');
+ } else {
+ options.qs['ql'] = ' order by ' + (orderBy || 'created desc');
+ }
+
+ if (limit) {
+ options.qs['limit'] = limit;
+ }
+ this.client().createCollection(options, function (err, collection, data) {
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'error getting ' + collection._type + ': ' + data.error_description);
+ } else {
+ $rootScope.$broadcast(type + '-received', collection);
+ }
+ //temporarily adding scope.apply to get working in prod, otherwise the events won't get broadcast
+ //todo - we need an apply strategy for 3rd party ug calls!
+ if(!$rootScope.$$phase) {
+ $rootScope.$apply();
+ }
+ });
+ },
+ runDataQuery: function (queryPath, searchString, queryLimit) {
+ this.getCollection('query', queryPath, null, searchString, queryLimit);
+ },
+ runDataPOSTQuery: function(queryPath, body) {
+ var self = this;
+ var options = {
+ method:'POST',
+ endpoint:queryPath,
+ body:body
+ };
+ this.client().request(options, function (err, data) {
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'error: ' + data.error_description);
+ $rootScope.$broadcast('error-running-query', data);
+ } else {
+
+ var queryPath = data.path;
+ self.getCollection('query', queryPath, null, 'order by modified DESC', null);
+
+ }
+ });
+ },
+ runDataPutQuery: function(queryPath, searchString, queryLimit, body) {
+ var self = this;
+ var options = {
+ method:'PUT',
+ endpoint:queryPath,
+ body:body
+ };
+
+ if (searchString) {
+ options.qs['ql'] = searchString;
+ }
+ if (queryLimit) {
+ options.qs['queryLimit'] = queryLimit;
+ }
+
+ this.client().request(options, function (err, data) {
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'error: ' + data.error_description);
+ } else {
+
+ var queryPath = data.path;
+ self.getCollection('query', queryPath, null, 'order by modified DESC', null);
+
+ }
+ });
+ },
+ runDataDeleteQuery: function(queryPath, searchString, queryLimit) {
+ var self = this;
+ var options = {
+ method:'DELETE',
+ endpoint:queryPath
+ };
+
+ if (searchString) {
+ options.qs['ql'] = searchString;
+ }
+ if (queryLimit) {
+ options.qs['queryLimit'] = queryLimit;
+ }
+
+ this.client().request(options, function (err, data) {
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'error: ' + data.error_description);
+ } else {
+
+ var queryPath = data.path;
+ self.getCollection('query', queryPath, null, 'order by modified DESC', null);
+
+ }
+ });
+ },
+ getUsers: function () {
+ this.getCollection('users','users','username');
+ var self = this;
+ $rootScope.$on("users-received",function(evt, users){
+ self.usersCollection = users;
+ })
+ },
+ getGroups: function () {
+ this.getCollection('groups','groups','title');
+ var self = this;
+ $rootScope.$on('groups-received', function(event, roles) {
+ self.groupsCollection = roles;
+ });
+
+ },
+ getRoles: function () {
+ this.getCollection('roles','roles','name');
+ var self = this;
+ $rootScope.$on('roles-received', function(event, roles) {
+ self.rolesCollection = roles
+ });
+ },
+ getNotifiers: function () {
+ var query = '',
+ limit = '100',
+ self = this;
+ this.getCollection('notifiers','notifiers','created', query, limit);
+ $rootScope.$on('notifiers-received', function(event, notifiers) {
+ self.notifiersCollection = notifiers;
+ });
+ },
+ getNotificationHistory: function (type) {
+ var query = null;
+ if (type) {
+ query = "select * where state = '" + type + "'";
+ }
+ this.getCollection('notifications','notifications', 'created desc', query);
+ var self = this;
+ $rootScope.$on('notifications-received', function(event, notifications) {
+ self.notificationCollection = notifications;
+ });
+ },
+ getNotificationReceipts: function (uuid) {
+ this.getCollection('receipts', 'notifications/'+uuid+'/receipts');
+ var self = this;
+ $rootScope.$on('receipts-received', function(event, receipts) {
+ self.receiptsCollection = receipts;
+ });
+ },
+ getIndexes: function (path) {
+ var options = {
+ method:'GET',
+ endpoint: path + '/indexes'
+ }
+ this.client().request(options, function (err, data) {
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'Problem getting indexes: ' + data.error);
+ } else {
+ $rootScope.$broadcast('indexes-received', data.data);
+ }
+ });
+ },
+ sendNotification: function(path, body) {
+ var options = {
+ method:'POST',
+ endpoint: path,
+ body:body
+ }
+ this.client().request(options, function (err, data) {
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'Problem creating notification: ' + data.error);
+ } else {
+ $rootScope.$broadcast('send-notification-complete');
+ }
+ });
+ },
+ getRolesUsers: function (username) {
+ var self = this;
+ var options = {
+ type:'roles/users/'+username,
+ qs:{ql:'order by username'}
+ }
+ this.client().createCollection(options, function (err, users) {
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'error getting users');
+ } else {
+ $rootScope.$broadcast('users-received', users);
+
+ }
+ });
+ },
+ getTypeAheadData: function (type, searchString, searchBy, orderBy) {
+
+ var self = this;
+ var search = '';
+ var qs = {limit: 100};
+ if (searchString) {
+ search = "select * where "+searchBy+" = '"+searchString+"'";
+ }
+ if (orderBy) {
+ search = search + " order by "+orderBy;
+ }
+ if (search) {
+ qs.ql = search;
+ }
+ var options = {
+ method:'GET',
+ endpoint: type,
+ qs:qs
+ }
+ this.client().request(options, function (err, data) {
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'error getting '+type);
+ } else {
+ var entities = data.entities;
+ $rootScope.$broadcast(type +'-typeahead-received', entities);
+ }
+ });
+ },
+ getUsersTypeAhead: function (searchString) {
+ this.getTypeAheadData('users', searchString, 'username', 'username');
+ },
+ getGroupsTypeAhead: function (searchString) {
+ this.getTypeAheadData('groups', searchString, 'path', 'path');
+ },
+ getRolesTypeAhead: function (searchString) {
+ this.getTypeAheadData('roles', searchString, 'name', 'name');
+ },
+ getGroupsForUser: function (user) {
+ var self = this;
+ var options = {
+ type:'users/'+user+'/groups'
+ }
+ this.client().createCollection(options, function (err, groups) {
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'error getting groups');
+ } else {
+
+ $rootScope.$broadcast('user-groups-received', groups);
+
+ }
+ });
+ },
+ addUserToGroup: function (user, group) {
+ var self = this;
+ var options = {
+ type:'users/'+user+'/groups/'+group
+ }
+ this.client().createEntity(options, function (err, entity) {
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'error adding user to group');
+ } else {
+ $rootScope.$broadcast('user-added-to-group-received');
+ }
+ });
+ },
+ addUserToRole: function (user, role) {
+ var options = {
+ method:'POST',
+ endpoint:'roles/'+role+'/users/'+user
+ };
+ this.client().request(options, function (err, data) {
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'error adding user to role');
+ } else {
+ $rootScope.$broadcast('role-update-received');
+ }
+ });
+ },
+ addGroupToRole: function (group, role) {
+ var options = {
+ method:'POST',
+ endpoint:'roles/'+role+'/groups/'+group
+ };
+ this.client().request(options, function (err, data) {
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'error adding group to role');
+ } else {
+ $rootScope.$broadcast('role-update-received');
+ }
+ });
+ },
+ followUser: function (user) {
+ var self = this;
+ var username = $rootScope.selectedUser.get('uuid');
+ var options = {
+ method:'POST',
+ endpoint:'users/'+username+'/following/users/'+user
+ };
+ this.client().request(options, function (err, data) {
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'error following user');
+ } else {
+ $rootScope.$broadcast('follow-user-received');
+ }
+ });
+ },
+ newPermission: function (permission, type, entity) { //"get,post,put:/mypermission"
+ var options = {
+ method:'POST',
+ endpoint:type+'/'+entity+'/permissions',
+ body:{"permission":permission}
+ };
+ this.client().request(options, function (err, data) {
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'error adding permission');
+ } else {
+ $rootScope.$broadcast('permission-update-received');
+ }
+ });
+ },
+ newUserPermission: function (permission, username) {
+ this.newPermission(permission,'users',username)
+ },
+ newGroupPermission: function (permission, path) {
+ this.newPermission(permission,'groups',path)
+ },
+ newRolePermission: function (permission, name) {
+ this.newPermission(permission,'roles',name)
+ },
+
+ deletePermission: function (permission, type, entity) { //"get,post,put:/mypermission"
+ var options = {
+ method:'DELETE',
+ endpoint:type+'/'+entity+'/permissions',
+ qs:{permission:permission}
+ };
+ this.client().request(options, function (err, data) {
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'error deleting permission');
+ } else {
+ $rootScope.$broadcast('permission-update-received');
+ }
+ });
+ },
+ deleteUserPermission: function (permission, user) {
+ this.deletePermission(permission,'users',user);
+ },
+ deleteGroupPermission: function (permission, group) {
+ this.deletePermission(permission,'groups',group);
+ },
+ deleteRolePermission: function (permission, rolename) {
+ this.deletePermission(permission,'roles',rolename);
+ },
+ removeUserFromRole: function (user, role) { //"get,post,put:/mypermission"
+ var options = {
+ method:'DELETE',
+ endpoint:'roles/'+role+'/users/'+user
+ };
+ this.client().request(options, function (err, data) {
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'error removing user from role');
+ } else {
+ $rootScope.$broadcast('role-update-received');
+ }
+ });
+ },
+ removeUserFromGroup: function (group, role) { //"get,post,put:/mypermission"
+ var options = {
+ method:'DELETE',
+ endpoint:'roles/'+role+'/groups/'+group
+ };
+ this.client().request(options, function (err, data) {
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'error removing role from the group');
+ } else {
+ $rootScope.$broadcast('role-update-received');
+ }
+ });
+ },
+ createAndroidNotifier: function (name, APIkey) {
+ var options = {
+ method:'POST',
+ endpoint:'notifiers',
+ body:{"apiKey":APIkey,"name":name,"provider":"google"}
+ };
+ this.client().request(options, function (err, data) {
+ if (err) {
+ console.error(data);
+ $rootScope.$broadcast('alert', 'error', 'error creating notifier ');
+ } else {
+ $rootScope.$broadcast('alert', 'success', 'New notifier created successfully.');
+ $rootScope.$broadcast('notifier-update');
+ }
+ });
+
+ },
+ createAppleNotifier: function (file, name, environment, certificatePassword ) {
+
+ var provider = 'apple';
+
+ var formData = new FormData();
+ formData.append("p12Certificate", file);
+
+ formData.append('name', name);
+ formData.append('provider', provider);
+ formData.append('environment', environment);
+ formData.append('certificatePassword', certificatePassword);
+
+ var options = {
+ method:'POST',
+ endpoint:'notifiers',
+ body:'{"apiKey":APIkey,"name":name,"provider":"google"}',
+ formData:formData
+ };
+ this.client().request(options, function (err, data) {
+ if (err) {
+ console.error(data);
+ $rootScope.$broadcast('alert', 'error', 'error creating notifier.' );
+ } else {
+ $rootScope.$broadcast('alert', 'success', 'New notifier created successfully.');
+ $rootScope.$broadcast('notifier-update');
+ }
+ });
+
+ },
+ deleteNotifier: function (name) {
+ var options = {
+ method:'DELETE',
+ endpoint: 'notifiers/'+name
+ };
+ this.client().request(options, function (err, data) {
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'error deleting notifier');
+ } else {
+ $rootScope.$broadcast('notifier-update');
+ }
+ });
+
+ },
+ initializeCurrentUser: function (callback) {
+ callback = callback || function(){};
+ if($rootScope.currentUser && !$rootScope.currentUser.reset){
+ callback($rootScope.currentUser);
+ return $rootScope.$broadcast('current-user-initialized', '');
+ }
+ var options = {
+ method:'GET',
+ endpoint:'management/users/'+ this.client().get('email'),
+ mQuery:true
+ };
+ this.client().request(options, function (err, data) {
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'Error getting user info');
+ } else {
+ $rootScope.currentUser = data.data;
+ $rootScope.currentUser.profileImg = utility.get_gravatar($rootScope.currentUser.email);
+ $rootScope.userEmail =$rootScope.currentUser.email;
+ callback($rootScope.currentUser);
+ $rootScope.$broadcast('current-user-initialized', $rootScope.currentUser);
+ }
+ });
+ },
+
+ updateUser: function (user) {
+ var body = $rootScope.currentUser;
+ body.username = user.username;
+ body.name = user.name;
+ body.email = user.email;
+ var options = {
+ method:'PUT',
+ endpoint:'management/users/' + user.uuid + '/',
+ mQuery:true,
+ body:body
+ };
+ var self = this;
+ this.client().request(options, function (err, data) {
+ self.client().set('email',user.email);
+ self.client().set('username',user.username);
+ if (err) {
+ return $rootScope.$broadcast('user-update-error',data);
+ }
+ $rootScope.currentUser.reset = true;
+ self.initializeCurrentUser(function(){
+ $rootScope.$broadcast('user-update-success', $rootScope.currentUser);
+ });
+ });
+ },
+
+ resetUserPassword: function (user) {
+ var pwdata = {};
+ pwdata.oldpassword = user.oldPassword;
+ pwdata.newpassword = user.newPassword;
+ pwdata.username = user.username;
+ var options = {
+ method:'PUT',
+ endpoint:'users/' + pwdata.uuid + '/',
+ body:pwdata
+ }
+ this.client().request(options, function (err, data) {
+ if (err) {
+ return $rootScope.$broadcast('alert', 'error', 'Error resetting password');
+ }
+ //remove old and new password fields so they don't end up as part of the entity object
+ $rootScope.currentUser.oldPassword = '';
+ $rootScope.currentUser.newPassword = '';
+ $rootScope.$broadcast('user-reset-password-success', $rootScope.currentUser);
+ });
+
+ },
+ getOrgCredentials: function () {
+ var options = {
+ method:'GET',
+ endpoint:'management/organizations/'+this.client().get('orgName')+'/credentials',
+ mQuery:true
+ };
+ this.client().request(options, function (err, data) {
+ if (err && data.credentials) {
+ $rootScope.$broadcast('alert', 'error', 'Error getting credentials');
+ } else {
+ $rootScope.$broadcast('org-creds-updated', data.credentials);
+ }
+ });
+ },
+ regenerateOrgCredentials: function () {
+ var self = this;
+ var options = {
+ method:'POST',
+ endpoint:'management/organizations/'+ this.client().get('orgName') + '/credentials',
+ mQuery:true
+ };
+ this.client().request(options, function(err, data) {
+ if (err && data.credentials) {
+ $rootScope.$broadcast('alert', 'error', 'Error regenerating credentials');
+ } else {
+ $rootScope.$broadcast('alert', 'success', 'Regeneration of credentials complete.');
+ $rootScope.$broadcast('org-creds-updated', data.credentials);
+ }
+ });
+ },
+ getAppCredentials: function () {
+ var options = {
+ method:'GET',
+ endpoint:'credentials'
+ };
+ this.client().request(options, function (err, data) {
+ if (err && data.credentials) {
+ $rootScope.$broadcast('alert', 'error', 'Error getting credentials');
+ } else {
+ $rootScope.$broadcast('app-creds-updated', data.credentials);
+ }
+ });
+ },
+
+ regenerateAppCredentials: function () {
+ var self = this;
+ var options = {
+ method:'POST',
+ endpoint:'credentials'
+ };
+ this.client().request(options, function(err, data) {
+ if (err && data.credentials) {
+ $rootScope.$broadcast('alert', 'error', 'Error regenerating credentials');
+ } else {
+ $rootScope.$broadcast('alert', 'success', 'Regeneration of credentials complete.');
+ $rootScope.$broadcast('app-creds-updated', data.credentials);
+ }
+ });
+ },
+
+ signUpUser: function(orgName,userName,name,email,password){
+ var formData = {
+ "organization": orgName,
+ "username": userName,
+ "name": name,
+ "email": email,
+ "password": password
+ };
+ var options = {
+ method:'POST',
+ endpoint:'management/organizations',
+ body:formData,
+ mQuery:true
+ };
+ var client = this.client();
+ client.request(options, function(err, data) {
+ if (err) {
+ $rootScope.$broadcast('register-error', data);
+ } else {
+ $rootScope.$broadcast('register-success',data);
+ }
+ });
+ },
+ resendActivationLink: function(id){
+ var options = {
+ method: 'GET',
+ endpoint: 'management/users/'+id+'/reactivate',
+ mQuery:true
+ };
+ this.client().request(options, function (err, data) {
+ if (err) {
+ $rootScope.$broadcast('resend-activate-error', data);
+ } else {
+ $rootScope.$broadcast('resend-activate-success',data);
+ }
+ });
+ },
+ getAppSettings: function(){
+ $rootScope.$broadcast('app-settings-received',{});
+ },
+ getActivities: function(){
+ this.client().request({method:'GET',endpoint:'activities', qs:{limit:200}},function(err,data){
+ if(err) return $rootScope.$broadcast('app-activities-error',data);
+ var entities = data.entities;
+ //set picture if there is none and change gravatar to secure
+ entities.forEach(function(entity) {
+ if (!entity.actor.picture) {
+ entity.actor.picture = window.location.protocol+ "//" + window.location.host + window.location.pathname + "img/user_profile.png"
+ } else {
+ entity.actor.picture = entity.actor.picture.replace(/^http:\/\/www.gravatar/i, 'https://secure.gravatar');
+ //note: changing this to use the image on apigee.com - since the gravatar default won't work on any non-public domains such as localhost
+ //this_data.picture = this_data.picture + encodeURI("?d="+window.location.protocol+"//" + window.location.host + window.location.pathname + "images/user_profile.png");
+ if (~entity.actor.picture.indexOf('http')) {
+ entity.actor.picture = entity.actor.picture;
+ } else {
+ entity.actor.picture = 'https://apigee.com/usergrid/img/user_profile.png';
+ }
+ }
+ });
+ $rootScope.$broadcast('app-activities-received',data.entities);
+ });
+ },
+ getEntityActivities: function(entity){
+ var endpoint = entity.get('type') + '/' + entity.get('uuid') + '/activities' ;
+ var options = {
+ method:'GET',
+ endpoint:endpoint,
+ qs:{limit:200}
+ };
+ this.client().request(options, function (err, data) {
+ if(err){
+ $rootScope.$broadcast(entity.get('type')+'-activities-error',data);
+ }
+ data.entities.forEach(function(entityInstance) {
+ entityInstance.createdDate = (new Date( entityInstance.created)).toUTCString();
+ });
+ $rootScope.$broadcast(entity.get('type')+'-activities-received',data.entities);
+ });
+ },
+ addUserActivity:function(user,content){
+ var options = {
+ "actor": {
+ "displayName": user.get('username'),
+ "uuid": user.get('uuid'),
+ "username":user.get('username')
+ },
+ "verb": "post",
+ "content": content
+ };
+ this.client().createUserActivity(user.get('username'), options, function(err, activity) { //first argument can be 'me', a uuid, or a username
+ if (err) {
+ $rootScope.$broadcast('user-activity-add-error', err);
+ } else {
+ $rootScope.$broadcast('user-activity-add-success', activity);
+ }
+ });
+ },
+ runShellQuery:function(method,path,payload){
+ var options = {
+ "verb": method,
+ "endpoint":path
+ };
+ if(payload){
+ options["body"]=payload;
+ }
+ this.client().request(options,function(err,data){
+ if(err) {
+ $rootScope.$broadcast('shell-error', data);
+ }else{
+ $rootScope.$broadcast('shell-success', data);
+ }
+ });
+ },
+ addOrganization:function(user,orgName){
+ var options = {
+ method: 'POST',
+ endpoint: 'management/users/'+user.uuid+'/organizations',
+ body:{organization:orgName},
+ mQuery:true
+ }, client = this.client(),self=this;
+ client.request(options,function(err,data){
+ if(err){
+ $rootScope.$broadcast('user-add-org-error', data);
+ }else{
+ $rootScope.$broadcast('user-add-org-success', $rootScope.organizations);
+ }
+ });
+ },
+ leaveOrganization:function(user,org){
+ var options = {
+ method: 'DELETE',
+ endpoint: 'management/users/'+user.uuid+'/organizations/'+org.uuid,
+ mQuery:true
+ }
+ this.client().request(options,function(err,data){
+ if(err){
+ $rootScope.$broadcast('user-leave-org-error', data);
+ }else{
+ delete $rootScope.organizations[org.name];
+ $rootScope.$broadcast('user-leave-org-success', $rootScope.organizations);
+ }
+ });
+ }
+ }
+});
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/508ef2f7/portal/js/global/util-directive.js
----------------------------------------------------------------------
diff --git a/portal/js/global/util-directive.js b/portal/js/global/util-directive.js
new file mode 100644
index 0000000..bbae34e
--- /dev/null
+++ b/portal/js/global/util-directive.js
@@ -0,0 +1,24 @@
+"use strict";
+
+AppServices.Directives.directive('ngFocus', ["$parse", function ($parse) {
+ return function(scope, element, attr) {
+ var fn = $parse(attr['ngFocus']);
+ element.bind('focus', function(event) {
+ scope.$apply(function() {
+ fn(scope, {$event:event});
+ });
+ });
+ }
+}])
+
+
+AppServices.Directives.directive('ngBlur', ["$parse", function ($parse) {
+ return function(scope, element, attr) {
+ var fn = $parse(attr['ngBlur']);
+ element.bind('blur', function(event) {
+ scope.$apply(function() {
+ fn(scope, {$event:event});
+ });
+ });
+ }
+}])
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/508ef2f7/portal/js/global/utility-service.js
----------------------------------------------------------------------
diff --git a/portal/js/global/utility-service.js b/portal/js/global/utility-service.js
new file mode 100755
index 0000000..254f5d2
--- /dev/null
+++ b/portal/js/global/utility-service.js
@@ -0,0 +1,52 @@
+AppServices.Services.factory('utility', function (configuration, $q, $http, $resource) {
+
+ return {
+
+ keys: function(o) {
+ var a = [];
+ for (var propertyName in o) {
+ a.push(propertyName);
+ }
+ return a;
+ },
+ get_gravatar: function(email, size) {
+ try {
+ var size = size || 50;
+ if (email.length) {
+ return 'https://secure.gravatar.com/avatar/' + MD5(email) + '?s=' + size ;
+ } else {
+ return 'https://apigee.com/usergrid/images/user_profile.png';
+ }
+ } catch(e) {
+ return 'https://apigee.com/usergrid/images/user_profile.png';
+ }
+ },
+ get_qs_params: function() {
+ var queryParams = {};
+ if (window.location.search) {
+ // split up the query string and store in an associative array
+ var params = window.location.search.slice(1).split("&");
+ for (var i = 0; i < params.length; i++) {
+ var tmp = params[i].split("=");
+ queryParams[tmp[0]] = unescape(tmp[1]);
+ }
+ }
+ return queryParams;
+ },
+
+ safeApply: function(fn) {
+ var phase = this.$root.$$phase;
+ if(phase == '$apply' || phase == '$digest') {
+ if(fn && (typeof(fn) === 'function')) {
+ fn();
+ }
+ } else {
+ this.$apply(fn);
+ }
+ }
+ };
+
+})
+
+
+
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/508ef2f7/portal/js/global/validate-directive.js
----------------------------------------------------------------------
diff --git a/portal/js/global/validate-directive.js b/portal/js/global/validate-directive.js
new file mode 100644
index 0000000..bf8e384
--- /dev/null
+++ b/portal/js/global/validate-directive.js
@@ -0,0 +1,40 @@
+
+AppServices.Directives.directive('ugValidate', ["$rootScope", function ($rootScope) {
+ return{
+ scope:true,
+ restrict: 'A',
+ require:'ng-model',
+ replace: true,
+ link: function linkFn(scope, element, attrs, ctrl) {
+ var validate = function(){
+ var id = element.attr('id');
+ var validator = id+'-validator';
+ var title = element.attr('title');
+ title = title && title.length ? title : 'Please enter data' ;
+ $('#'+validator).remove();
+ if(!ctrl.$valid){
+ var validatorElem = '<div id="'+validator+'"><span class="validator-error-message">'+title+'</span></div>';
+ $( '#'+id ).after( validatorElem);
+ element.addClass('has-error');
+ }else{
+ element.removeClass('has-error');
+ $('#'+validator).remove();
+ }
+ };
+
+ var firing = false;
+ element.bind('blur', function (evt) {
+ validate(scope,element,attrs,ctrl);
+ }).bind('input', function (evt) {
+ if(firing){
+ return ;
+ }
+ firing = true;
+ setTimeout(function(){
+ validate(scope,element,attrs,ctrl);
+ firing=false;
+ },500)
+ });
+ }
+ };
+}]);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/508ef2f7/portal/js/groups/groups-activities-controller.js
----------------------------------------------------------------------
diff --git a/portal/js/groups/groups-activities-controller.js b/portal/js/groups/groups-activities-controller.js
new file mode 100644
index 0000000..f9b3c94
--- /dev/null
+++ b/portal/js/groups/groups-activities-controller.js
@@ -0,0 +1,27 @@
+'use strict'
+
+AppServices.Controllers.controller('GroupsActivitiesCtrl', ['ug', '$scope', '$rootScope', '$location',
+ function (ug, $scope, $rootScope, $location) {
+
+ $scope.activitiesSelected = 'active';
+
+ if (!$rootScope.selectedGroup) {
+ $location.path('/groups');
+ return;
+ } else {
+ $rootScope.selectedGroup.activities = [];
+ $rootScope.selectedGroup.getActivities(function(err, data){
+ if (err) {
+
+ } else {
+// $rootScope.selectedGroup.activities = data;
+ if(!$rootScope.$$phase) {
+ $rootScope.$apply();
+ }
+ }
+
+ });
+ }
+
+
+ }]);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/508ef2f7/portal/js/groups/groups-activities.html
----------------------------------------------------------------------
diff --git a/portal/js/groups/groups-activities.html b/portal/js/groups/groups-activities.html
new file mode 100644
index 0000000..675bedf
--- /dev/null
+++ b/portal/js/groups/groups-activities.html
@@ -0,0 +1,24 @@
+<div class="content-page" ng-controller="GroupsActivitiesCtrl">
+
+ <br>
+ <div>
+ <table class="table table-striped">
+ <tbody>
+ <tr class="table-header">
+ <td>Date</td>
+ <td>Content</td>
+ <td>Verb</td>
+ <td>UUID</td>
+ </tr>
+ <tr class="zebraRows" ng-repeat="activity in selectedGroup.activities">
+ <td>{{activity.createdDate}}</td>
+ <td>{{activity.content}}</td>
+ <td>{{activity.verb}}</td>
+ <td>{{activity.uuid}}</td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+
+
+</div>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/508ef2f7/portal/js/groups/groups-controller.js
----------------------------------------------------------------------
diff --git a/portal/js/groups/groups-controller.js b/portal/js/groups/groups-controller.js
new file mode 100644
index 0000000..ae9ab35
--- /dev/null
+++ b/portal/js/groups/groups-controller.js
@@ -0,0 +1,119 @@
+'use strict'
+
+AppServices.Controllers.controller('GroupsCtrl', ['ug', '$scope', '$rootScope', '$location', '$route',
+ function (ug, $scope, $rootScope, $location, $route) {
+
+ $scope.groupsCollection = {};
+ $rootScope.selectedGroup = {};
+ $scope.previous_display = 'none';
+ $scope.next_display = 'none';
+ $scope.hasGroups = false;
+ $scope.newGroup = {path:'',title:''}
+
+ ug.getGroups();
+
+ $scope.currentGroupsPage = {};
+// $scope.$route = $route;
+
+ $scope.selectGroupPage = function(route){
+ //lokup the template URL with the route. trying to preserve routes in the markup and not hard link to .html
+ $scope.currentGroupsPage.template = $route.routes[route].templateUrl;
+ $scope.currentGroupsPage.route = route;
+ }
+
+ $scope.newGroupDialog = function(modalId,form){
+ //todo: put more validate here
+ if ($scope.newGroup.path && $scope.newGroup.title) {
+ //$scope.path = $scope.path.replace(' ','');
+ ug.createGroup($scope.removeFirstSlash($scope.newGroup.path), $scope.newGroup.title);
+ $scope.hideModal(modalId);
+ $scope.newGroup = {path:'',title:''}
+ } else {
+ $rootScope.$broadcast('alert', 'error', 'Missing required information.');
+ }
+ };
+
+ $scope.deleteGroupsDialog = function(modalId){
+ $scope.deleteEntities($scope.groupsCollection, 'group-deleted', 'error deleting group');
+ $scope.hideModal(modalId);
+ $scope.newGroup = {path:'',title:''}
+ };
+ $scope.$on('group-deleted',function(){
+ $rootScope.$broadcast('alert', 'success', 'Group deleted successfully.');
+ });
+ $scope.$on('group-deleted-error',function(){
+ ug.getGroups();
+ });
+
+ $scope.$on("groups-create-success",function(){
+ $rootScope.$broadcast('alert', 'success', 'Group created successfully.');
+ });
+
+ $scope.$on("groups-create-error",function(){
+ $rootScope.$broadcast('alert', 'error', 'Error creating group. Make sure you don\'t have spaces in the path.');
+ });
+
+ $scope.$on('groups-received', function(event, groups) {
+ $scope.groupBoxesSelected = false;
+ $scope.groupsCollection = groups;
+ $scope.newGroup.path = '';
+ $scope.newGroup.title = '';
+ if(groups._list.length > 0 && (!$rootScope.selectedGroup._data || !groups._list.some(function(group){ return $rootScope.selectedGroup._data.uuid === group._data.uuid }))){ // if groups have been received already do not reselect
+ $scope.selectGroup(groups._list[0]._data.uuid)
+ }
+ $scope.hasGroups = groups._list.length > 0;
+ $scope.received = true;
+
+ $scope.checkNextPrev();
+ $scope.applyScope();
+ });
+
+ $scope.resetNextPrev = function() {
+ $scope.previous_display = 'none';
+ $scope.next_display = 'none';
+ }
+ $scope.checkNextPrev = function() {
+ $scope.resetNextPrev();
+ if ($scope.groupsCollection.hasPreviousPage()) {
+ $scope.previous_display = 'block';
+ }
+ if($scope.groupsCollection.hasNextPage()) {
+ $scope.next_display = 'block';
+ }
+ }
+
+ $scope.selectGroup = function(uuid){
+ $rootScope.selectedGroup = $scope.groupsCollection.getEntityByUUID(uuid);
+ $scope.currentGroupsPage.template = 'groups/groups-details.html';
+ $scope.currentGroupsPage.route = '/groups/details';
+ $rootScope.$broadcast('group-selection-changed', $rootScope.selectedGroup);
+ }
+
+ $scope.getPrevious = function () {
+ $scope.groupsCollection.getPreviousPage(function(err) {
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'error getting previous page of groups');
+ }
+ $scope.checkNextPrev();
+ $scope.applyScope();
+ });
+ };
+
+ $scope.getNext = function () {
+
+ $scope.groupsCollection.getNextPage(function(err) {
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'error getting next page of groups');
+ }
+ $scope.checkNextPrev();
+ $scope.applyScope();
+ });
+ };
+
+ $scope.$on('group-deleted', function(event) {
+ $route.reload();
+ $scope.master = '';
+ });
+
+
+ }]);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/508ef2f7/portal/js/groups/groups-details-controller.js
----------------------------------------------------------------------
diff --git a/portal/js/groups/groups-details-controller.js b/portal/js/groups/groups-details-controller.js
new file mode 100644
index 0000000..e9164ac
--- /dev/null
+++ b/portal/js/groups/groups-details-controller.js
@@ -0,0 +1,38 @@
+'use strict'
+
+AppServices.Controllers.controller('GroupsDetailsCtrl', ['ug', '$scope', '$rootScope', '$location',
+ function (ug, $scope, $rootScope, $location) {
+
+ var selectedGroup = $rootScope.selectedGroup.clone();
+ $scope.detailsSelected = 'active';
+ $scope.json = selectedGroup._json;
+ $scope.group = selectedGroup._data;
+ $scope.group.path = $scope.group.path.indexOf('/')!=0 ? '/'+$scope.group.path : $scope.group.path;
+ $scope.group.title = $scope.group.title;
+
+ if (!$rootScope.selectedGroup) {
+ $location.path('/groups');
+ return;
+ }
+ $scope.$on('group-selection-changed',function(evt,selectedGroup){
+ $scope.group.path = selectedGroup._data.path.indexOf('/')!=0 ? '/'+selectedGroup._data.path : selectedGroup._data.path;
+ $scope.group.title = selectedGroup._data.title;
+ $scope.detailsSelected = 'active';
+ $scope.json = selectedGroup._json || selectedGroup._data.stringifyJSON();
+
+ });
+
+ $rootScope.saveSelectedGroup = function(){
+ $rootScope.selectedGroup._data.title = $scope.group.title;
+ $rootScope.selectedGroup._data.path = $scope.removeFirstSlash( $scope.group.path);
+ $rootScope.selectedGroup.save(function(err) {
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'error saving group');
+ } else {
+ $rootScope.$broadcast('alert', 'success', 'group saved');
+ }
+ });
+
+ }
+
+ }]);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/508ef2f7/portal/js/groups/groups-details.html
----------------------------------------------------------------------
diff --git a/portal/js/groups/groups-details.html b/portal/js/groups/groups-details.html
new file mode 100644
index 0000000..1e55822
--- /dev/null
+++ b/portal/js/groups/groups-details.html
@@ -0,0 +1,28 @@
+<div class="content-page" ng-controller="GroupsDetailsCtrl">
+
+ <div>
+ <form name="updateGroupDetailForm" ng-submit="saveSelectedGroup()" novalidate>
+ <div style="float: left; padding-right: 30px;">
+ <h4 class="ui-dform-legend">Group Information</h4>
+ <label for="group-title" class="ui-dform-label">Group Title</label>
+ <input type="text" id="group-title" ng-pattern="titleRegex" ng-attr-title="{{titleRegexDescription}}" required class="ui-dform-text" ng-model="group.title" ug-validate>
+ <br/>
+ <label for="group-path" class="ui-dform-label">Group Path</label>
+ <input type="text" id="group-path" required ng-attr-title="{{pathRegexDescription}}" placeholder="ex: /mydata" ng-pattern="pathRegex" class="ui-dform-text" ng-model="group.path" ug-validate>
+ <br/>
+ </div>
+ <br style="clear:both"/>
+
+ <div style="width:100%;float:left;padding: 20px 0">
+ <input type="submit" value="Save Group" style="margin-right: 15px;" ng-disabled="!updateGroupDetailForm.$valid" class="btn btn-primary" />
+ </div>
+
+ <div class="content-container">
+ <h4>JSON Group Object</h4>
+ <pre>{{json}}</pre>
+ </div>
+ </form>
+ </div>
+
+
+</div>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/508ef2f7/portal/js/groups/groups-members-controller.js
----------------------------------------------------------------------
diff --git a/portal/js/groups/groups-members-controller.js b/portal/js/groups/groups-members-controller.js
new file mode 100644
index 0000000..b4c4c16
--- /dev/null
+++ b/portal/js/groups/groups-members-controller.js
@@ -0,0 +1,113 @@
+'use strict'
+
+AppServices.Controllers.controller('GroupsMembersCtrl', ['ug', '$scope', '$rootScope', '$location',
+ function (ug, $scope, $rootScope, $location) {
+
+ $scope.membersSelected = 'active';
+ $scope.previous_display = 'none';
+ $scope.next_display = 'none';
+ $scope.user = '';
+ $scope.master = '';
+ $scope.hasMembers = false
+
+
+ //todo find others and combine this into one controller
+ ug.getUsersTypeAhead();
+
+ $scope.usersTypeaheadValues = [];
+ $scope.$on('users-typeahead-received', function(event, users) {
+ $scope.usersTypeaheadValues = users;
+ $scope.applyScope();
+ });
+
+ $scope.addGroupToUserDialog = function(modalId){
+ if ($scope.user) {
+ var path = $rootScope.selectedGroup.get('path');
+ ug.addUserToGroup($scope.user.uuid, path);
+ $scope.user = '';
+ $scope.hideModal(modalId)
+ } else {
+ $rootScope.$broadcast('alert', 'error', 'Please select a user.');
+ }
+ };
+
+ $scope.removeUsersFromGroupDialog = function(modalId){
+ $scope.deleteEntities($scope.groupsCollection.users, 'group-update-received', 'Error removing user from group');
+ $scope.hideModal(modalId)
+ };
+
+ $scope.get = function() {
+ if(!$rootScope.selectedGroup.get){
+ return;
+ }
+ var options = {
+ type:'groups/'+$rootScope.selectedGroup.get('path') +'/users'
+ }
+ $scope.groupsCollection.addCollection('users', options, function(err) {
+ $scope.groupMembersSelected = false;
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'error getting users for group');
+ } else {
+ $scope.hasMembers = $scope.groupsCollection.users._list.length > 0;
+ $scope.checkNextPrev();
+ $scope.applyScope();
+ }
+ });
+ }
+
+ $scope.resetNextPrev = function() {
+ $scope.previous_display = 'none';
+ $scope.next_display = 'none';
+ }
+ $scope.checkNextPrev = function() {
+ $scope.resetNextPrev();
+ if ($scope.groupsCollection.users.hasPreviousPage()) {
+ $scope.previous_display = 'block';
+ }
+
+ if($scope.groupsCollection.users.hasNextPage()) {
+ $scope.next_display = 'block';
+ }
+ }
+
+ if (!$rootScope.selectedGroup) {
+ $location.path('/groups');
+ return;
+ } else {
+ $scope.get();
+ }
+
+ $scope.getPrevious = function () {
+ $scope.groupsCollection.users.getPreviousPage(function(err) {
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'error getting previous page of users');
+ }
+ $scope.checkNextPrev();
+ if(!$rootScope.$$phase) {
+ $rootScope.$apply();
+ }
+ });
+ };
+
+ $scope.getNext = function () {
+ $scope.groupsCollection.users.getNextPage(function(err) {
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'error getting next page of users');
+ }
+ $scope.checkNextPrev();
+ if(!$rootScope.$$phase) {
+ $rootScope.$apply();
+ }
+ });
+ };
+
+ $scope.$on('group-update-received', function(event) {
+ $scope.get();
+ });
+
+ $scope.$on('user-added-to-group-received', function(event) {
+ $scope.get();
+ });
+
+
+ }]);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/508ef2f7/portal/js/groups/groups-members.html
----------------------------------------------------------------------
diff --git a/portal/js/groups/groups-members.html b/portal/js/groups/groups-members.html
new file mode 100644
index 0000000..d2f5644
--- /dev/null
+++ b/portal/js/groups/groups-members.html
@@ -0,0 +1,60 @@
+<div class="content-page" ng-controller="GroupsMembersCtrl">
+
+
+ <bsmodal id="removeFromGroup"
+ title="Confirmation"
+ close="hideModal"
+ closelabel="Cancel"
+ extrabutton="removeUsersFromGroupDialog"
+ extrabuttonlabel="Delete"
+ ng-cloak>
+ <p>Are you sure you want to remove the users from the seleted group(s)?</p>
+ </bsmodal>
+
+ <bsmodal id="addGroupToUser"
+ title="Add user to group"
+ close="hideModal"
+ closelabel="Cancel"
+ extrabutton="addGroupToUserDialog"
+ extrabuttonlabel="Add"
+ ng-cloak>
+ <div class="btn-group">
+ <a class="btn dropdown-toggle filter-selector" data-toggle="dropdown">
+ <span class="filter-label">{{$parent.user != '' ? $parent.user.username : 'Select a user...'}}</span>
+ <span class="caret"></span>
+ </a>
+ <ul class="dropdown-menu">
+ <li ng-repeat="user in $parent.usersTypeaheadValues" class="filterItem"><a ng-click="$parent.$parent.user = user">{{user.username}}</a></li>
+ </ul>
+ </div>
+ </bsmodal>
+
+
+ <div class="button-strip">
+ <button class="btn btn-primary" ng-click="showModal('addGroupToUser')">Add User to Group</button>
+ <button class="btn btn-primary" ng-disabled="!hasMembers || !valueSelected(groupsCollection.users._list)" ng-click="showModal('removeFromGroup')">Remove User(s) from Group</button>
+ </div>
+ <table class="table table-striped">
+ <tr class="table-header">
+ <td style="width: 30px;"><input type="checkbox" ng-show="hasMembers" id="selectAllCheckbox" ng-model="groupMembersSelected" ng-click="selectAllEntities(groupsCollection.users._list,this,'groupMembersSelected')"></td>
+ <td style="width: 50px;"></td>
+ <td>Username</td>
+ <td>Display Name</td>
+ </tr>
+ <tr class="zebraRows" ng-repeat="user in groupsCollection.users._list">
+ <td>
+ <input
+ type="checkbox"
+ ng-model="user.checked"
+ >
+ </td>
+ <td><img style="width:30px;height:30px;" ng-src="{{user._portal_image_icon}}"></td>
+ <td>{{user.get('username')}}</td>
+ <td>{{user.get('name')}}</td>
+ </tr>
+ </table>
+ <div style="padding: 10px 5px 10px 5px">
+ <button class="btn btn-primary" ng-click="getPrevious()" style="display:{{previous_display}}">< Previous</button>
+ <button class="btn btn-primary" ng-click="getNext()" style="display:{{next_display}}; float:right;">Next ></button>
+ </div>
+</div>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/508ef2f7/portal/js/groups/groups-roles-controller.js
----------------------------------------------------------------------
diff --git a/portal/js/groups/groups-roles-controller.js b/portal/js/groups/groups-roles-controller.js
new file mode 100644
index 0000000..e3a8004
--- /dev/null
+++ b/portal/js/groups/groups-roles-controller.js
@@ -0,0 +1,184 @@
+'use strict'
+
+AppServices.Controllers.controller('GroupsRolesCtrl', ['ug', '$scope', '$rootScope', '$location',
+ function (ug, $scope, $rootScope, $location) {
+
+
+ $scope.rolesSelected = 'active';
+ $scope.roles_previous_display = 'none';
+ $scope.roles_next_display = 'none';
+ $scope.name = '';
+ $scope.master = '';
+ $scope.hasRoles = false;
+ $scope.hasPermissions = false;
+ $scope.permissions = {};
+
+
+ $scope.addGroupToRoleDialog = function(modalId){
+ if ($scope.name) {
+ var path = $rootScope.selectedGroup.get('path');
+ ug.addGroupToRole(path, $scope.name);
+ $scope.hideModal(modalId)
+ $scope.name='';
+ } else {
+ $rootScope.$broadcast('alert', 'error', 'You must specify a role name.');
+ }
+ };
+
+
+ $scope.leaveRoleDialog = function(modalId){
+ var path = $rootScope.selectedGroup.get('path');
+ var roles = $scope.groupsCollection.roles._list;
+ for (var i=0;i<roles.length;i++) {
+ if (roles[i].checked) {
+ ug.removeUserFromGroup(path, roles[i]._data.name);
+ }
+ }
+ $scope.hideModal(modalId)
+ };
+
+ $scope.addGroupPermissionDialog = function(modalId){
+ if ($scope.permissions.path) {
+
+ var permission = $scope.createPermission(null,null,$scope.removeFirstSlash($scope.permissions.path),$scope.permissions);
+ var path = $rootScope.selectedGroup.get('path');
+ ug.newGroupPermission(permission, path);
+ $scope.hideModal(modalId)
+ if($scope.permissions){
+ $scope.permissions = {};
+ }
+ } else {
+ $rootScope.$broadcast('alert', 'error', 'You must specify a name for the permission.');
+ }
+ };
+
+ $scope.deleteGroupPermissionDialog = function(modalId){
+ var path = $rootScope.selectedGroup.get('path');
+ var permissions = $rootScope.selectedGroup.permissions;
+ for (var i=0;i<permissions.length;i++) {
+ if (permissions[i].checked) {
+ ug.deleteGroupPermission(permissions[i].perm, path);
+ }
+ }
+ $scope.hideModal(modalId)
+ };
+
+ $scope.resetNextPrev = function() {
+ $scope.roles_previous_display = 'none';
+ $scope.roles_next_display = 'none';
+ $scope.permissions_previous_display = 'none';
+ $scope.permissions_next_display = 'none';
+ }
+ $scope.resetNextPrev();
+ $scope.checkNextPrevRoles = function() {
+ $scope.resetNextPrev();
+ if ($scope.groupsCollection.roles.hasPreviousPage()) {
+ $scope.roles_previous_display = 'block';
+ }
+ if($scope.groupsCollection.roles.hasNextPage()) {
+ $scope.roles_next_display = 'block';
+ }
+ }
+ $scope.checkNextPrevPermissions = function() {
+ if ($scope.groupsCollection.permissions.hasPreviousPage()) {
+ $scope.permissions_previous_display = 'block';
+ }
+ if($scope.groupsCollection.permissions.hasNextPage()) {
+ $scope.permissions_next_display = 'block';
+ }
+ }
+
+ $scope.getRoles = function() {
+
+ var path = $rootScope.selectedGroup.get('path');
+ var options = {
+ type:'groups/'+ path +'/roles'
+ }
+ $scope.groupsCollection.addCollection('roles', options, function(err) {
+ $scope.groupRoleSelected = false;
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'error getting roles for group');
+ } else {
+ $scope.hasRoles = $scope.groupsCollection.roles._list.length > 0;
+ $scope.checkNextPrevRoles();
+ $scope.applyScope();
+ }
+ });
+ }
+
+ $scope.getPermissions = function() {
+
+ $rootScope.selectedGroup.permissions = [];
+ $rootScope.selectedGroup.getPermissions(function(err, data){
+ $scope.groupPermissionsSelected = false;
+ $scope.hasPermissions = $scope.selectedGroup.permissions.length;
+ if (err) {
+
+ } else {
+ $scope.applyScope();
+ }
+ });
+
+ }
+
+ $scope.getPreviousRoles = function () {
+ $scope.groupsCollection.roles.getPreviousPage(function(err) {
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'error getting previous page of roles');
+ }
+ $scope.checkNextPrevRoles();
+ $scope.applyScope();
+ });
+ };
+ $scope.getNextRoles = function () {
+ $scope.groupsCollection.roles.getNextPage(function(err) {
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'error getting next page of roles');
+ }
+ $scope.checkNextPrevRoles();
+ $scope.applyScope();
+ });
+ };
+ $scope.getPreviousPermissions = function () {
+ $scope.groupsCollection.permissions.getPreviousPage(function(err) {
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'error getting previous page of permissions');
+ }
+ $scope.checkNextPrevPermissions();
+ $scope.applyScope();
+ });
+ };
+ $scope.getNextPermissions = function () {
+ $scope.groupsCollection.permissions.getNextPage(function(err) {
+ if (err) {
+ $rootScope.$broadcast('alert', 'error', 'error getting next page of permissions');
+ }
+ $scope.checkNextPrevPermissions();
+ $scope.applyScope();
+ });
+ };
+
+ $scope.$on('role-update-received', function(event) {
+ $scope.getRoles();
+ });
+
+ $scope.$on('permission-update-received', function(event) {
+ $scope.getPermissions();
+ });
+
+ $scope.$on('groups-received',function(evt,data){
+ $scope.groupsCollection = data;
+ $scope.getRoles();
+ $scope.getPermissions();
+ })
+
+ if (!$rootScope.selectedGroup) {
+ $location.path('/groups');
+ return;
+ } else {
+ ug.getRolesTypeAhead();
+ ug.getGroups();
+ }
+
+
+ }]);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/508ef2f7/portal/js/groups/groups-roles.html
----------------------------------------------------------------------
diff --git a/portal/js/groups/groups-roles.html b/portal/js/groups/groups-roles.html
new file mode 100644
index 0000000..f8b586b
--- /dev/null
+++ b/portal/js/groups/groups-roles.html
@@ -0,0 +1,127 @@
+<div class="content-page" ng-controller="GroupsRolesCtrl">
+
+ <bsmodal id="addGroupToRole"
+ title="Add group to role"
+ close="hideModal"
+ closelabel="Cancel"
+ extrabutton="addGroupToRoleDialog"
+ extrabuttonlabel="Add"
+ ng-cloak>
+ <div class="btn-group">
+ <a class="btn dropdown-toggle filter-selector" data-toggle="dropdown">
+ <span class="filter-label">{{$parent.name != '' ? $parent.name : 'Role name...'}}</span>
+ <span class="caret"></span>
+ </a>
+ <ul class="dropdown-menu">
+ <li ng-repeat="role in $parent.rolesTypeaheadValues" class="filterItem"><a ng-click="$parent.$parent.name = role.name">{{role.name}}</a></li>
+ </ul>
+ </div>
+ </bsmodal>
+
+ <bsmodal id="leaveRoleFromGroup"
+ title="Confirmation"
+ close="hideModal"
+ closelabel="Cancel"
+ extrabutton="leaveRoleDialog"
+ extrabuttonlabel="Leave"
+ ng-cloak>
+ <p>Are you sure you want to remove the group from the role(s)?</p>
+ </bsmodal>
+
+
+ <div class="button-strip">
+ <button class="btn btn-primary" ng-click="showModal('addGroupToRole')">Add Role to Group</button>
+ <button class="btn btn-primary" ng-disabled="!hasRoles || !valueSelected(groupsCollection.roles._list)" ng-click="showModal('leaveRoleFromGroup')">Remove Role(s) from Group</button>
+ </div>
+ <h4>Roles</h4>
+ <table class="table table-striped">
+ <tbody>
+ <tr class="table-header">
+ <td style="width: 30px;"><input type="checkbox" ng-show="hasRoles" id="groupsSelectAllCheckBox" ng-model="groupRoleSelected" ng-click="selectAllEntities(groupsCollection.roles._list,this,'groupRoleSelected')" ></td>
+ <td>Role Name</td>
+ <td>Role title</td>
+ </tr>
+ <tr class="zebraRows" ng-repeat="role in groupsCollection.roles._list">
+ <td>
+ <input
+ type="checkbox"
+ ng-model="role.checked"
+ >
+ </td>
+ <td>{{role._data.name}}</td>
+ <td>{{role._data.title}}</td>
+ </tr>
+ </tbody>
+ </table>
+ <div style="padding: 10px 5px 10px 5px">
+ <button class="btn btn-primary" ng-click="getPreviousRoles()" style="display:{{roles_previous_display}}">< Previous</button>
+ <button class="btn btn-primary" ng-click="getNextRoles()" style="display:{{roles_next_display}};float:right;">Next ></button>
+ </div>
+
+
+ <bsmodal id="deletePermission"
+ title="Confirmation"
+ close="hideModal"
+ closelabel="Cancel"
+ extrabutton="deleteGroupPermissionDialog"
+ extrabuttonlabel="Delete"
+ ng-cloak>
+ <p>Are you sure you want to delete the permission(s)?</p>
+ </bsmodal>
+
+
+ <bsmodal id="addPermission"
+ title="New Permission"
+ close="hideModal"
+ closelabel="Cancel"
+ extrabutton="addGroupPermissionDialog"
+ extrabuttonlabel="Add"
+ ng-cloak>
+ <p>Path: <input ng-model="$parent.permissions.path" placeholder="ex: /mydata" id="groupsrolespermissions" type="text" ng-pattern="pathRegex" ng-attr-title="{{pathRegexDescription}}" required ug-validate /></p>
+ <div class="control-group">
+ <input type="checkbox" ng-model="$parent.permissions.getPerm"> GET
+ </div>
+ <div class="control-group">
+ <input type="checkbox" ng-model="$parent.permissions.postPerm"> POST
+ </div>
+ <div class="control-group">
+ <input type="checkbox" ng-model="$parent.permissions.putPerm"> PUT
+ </div>
+ <div class="control-group">
+ <input type="checkbox" ng-model="$parent.permissions.deletePerm"> DELETE
+ </div>
+ </bsmodal>
+
+
+ <div class="button-strip">
+ <button class="btn btn-primary" ng-click="showModal('addPermission')">Add Permission</button>
+ <button class="btn btn-primary" ng-disabled="!hasPermissions || !valueSelected(selectedGroup.permissions)" ng-click="showModal('deletePermission')">Delete Permission(s)</button>
+ </div>
+ <h4>Permissions</h4>
+ <table class="table table-striped">
+ <tbody>
+ <tr class="table-header">
+ <td style="width: 30px;"><input ng-show="hasPermissions" type="checkbox" id="permissionsSelectAllCheckBox" ng-model="groupPermissionsSelected" ng-click="selectAllEntities(selectedGroup.permissions,this,'groupPermissionsSelected')" ></td>
+ <td>Path</td>
+ <td>GET</td>
+ <td>POST</td>
+ <td>PUT</td>
+ <td>DELETE</td>
+ </tr>
+ <tr class="zebraRows" ng-repeat="permission in selectedGroup.permissions">
+ <td>
+ <input
+ type="checkbox"
+ ng-model="permission.checked"
+ >
+ </td>
+ <td>{{permission.path}}</td>
+ <td>{{permission.operations.get}}</td>
+ <td>{{permission.operations.post}}</td>
+ <td>{{permission.operations.put}}</td>
+ <td>{{permission.operations.delete}}</td>
+ </tr>
+ </tbody>
+ </table>
+
+</div>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/508ef2f7/portal/js/groups/groups-tabs.html
----------------------------------------------------------------------
diff --git a/portal/js/groups/groups-tabs.html b/portal/js/groups/groups-tabs.html
new file mode 100644
index 0000000..79d0a78
--- /dev/null
+++ b/portal/js/groups/groups-tabs.html
@@ -0,0 +1,31 @@
+<div class="content-page">
+
+ <section class="row-fluid">
+
+ <div class="span12">
+ <div class="page-filters">
+ <h1 class="title" class="pull-left"><i class="pictogram title">👥</i> Groups</h1>
+ </div>
+ </div>
+
+ </section>
+
+ <div id="user-panel" class="panel-buffer">
+ <ul id="user-panel-tab-bar" class="nav nav-tabs">
+ <li><a href="javaScript:void(0);" ng-click="gotoPage('groups')">Group List</a></li>
+ <li ng-class="detailsSelected"><a href="javaScript:void(0);" ng-click="gotoPage('groups/details')">Details</a></li>
+ <li ng-class="membersSelected"><a href="javaScript:void(0);" ng-click="gotoPage('groups/members')">Users</a></li>
+ <li ng-class="activitiesSelected"><a href="javaScript:void(0);" ng-click="gotoPage('groups/activities')">Activities</a></li>
+ <li ng-class="rolesSelected"><a href="javaScript:void(0);" ng-click="gotoPage('groups/roles')">Roles & Permissions</a></li>
+ </ul>
+ </div>
+
+ <div style="float: left; margin-right: 10px;">
+ <div style="float: left;">
+ <div class="user-header-title"><strong>Group Path: </strong>{{selectedGroup.get('path')}}</div>
+ <div class="user-header-title"><strong>Group Title: </strong>{{selectedGroup.get('title')}}</div>
+ </div>
+ </div>
+</div>
+<br>
+<br>
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/508ef2f7/portal/js/groups/groups.html
----------------------------------------------------------------------
diff --git a/portal/js/groups/groups.html b/portal/js/groups/groups.html
new file mode 100644
index 0000000..4f81b18
--- /dev/null
+++ b/portal/js/groups/groups.html
@@ -0,0 +1,92 @@
+<div class="content-page">
+
+ <section class="row-fluid">
+
+ <div class="span12">
+ <div class="page-filters">
+ <h1 class="title" class="pull-left"><i class="pictogram title">👥</i> Groups</h1>
+ </div>
+ </div>
+
+ </section>
+
+
+
+ <bsmodal id="newGroup"
+ title="New Group"
+ close="hideModal"
+ closelabel="Cancel"
+ extrabutton="newGroupDialog"
+ extrabuttonlabel="Add"
+ ng-model="dialog"
+ ng-cloak>
+ <fieldset>
+ <div class="control-group">
+ <label for="title">Title</label>
+ <div class="controls">
+ <input type="text" id="title" ng-pattern="titleRegex" ng-attr-title="{{titleRegexDescription}}" required ng-model="newGroup.title"class="input-xlarge" ug-validate/>
+ </div>
+ </div>
+ <div class="control-group">
+ <label for="path">Path</label>
+ <div class="controls">
+ <input id="path" type="text" ng-attr-title="{{pathRegexDescription}}" placeholder="ex: /mydata" ng-pattern="pathRegex" required ng-model="newGroup.path" class="input-xlarge" ug-validate/>
+ </div>
+ </div>
+ </fieldset>
+ </bsmodal>
+
+ <bsmodal id="deleteGroup"
+ title="Delete Group"
+ close="hideModal"
+ closelabel="Cancel"
+ extrabutton="deleteGroupsDialog"
+ extrabuttonlabel="Delete"
+ ng-cloak>
+ <p>Are you sure you want to delete the group(s)?</p>
+ </bsmodal>
+
+
+ <section class="row-fluid">
+ <div class="span3 user-col">
+
+ <div class="button-toolbar span12">
+ <a title="Select All" class="btn btn-primary select-all toolbar" ng-show="hasGroups" ng-click="selectAllEntities(groupsCollection._list,this,'groupBoxesSelected',true)"> <i class="pictogram">⊟</i></a>
+ <button title="Delete" class="btn btn-primary toolbar" ng-disabled="!hasGroups || !valueSelected(groupsCollection._list)" ng-click="showModal('deleteGroup')"><i class="pictogram">☕</i></button>
+ <button title="Add" class="btn btn-primary toolbar" ng-click="showModal('newGroup')"><i class="pictogram"></i></button>
+ </div>
+ <ul class="user-list">
+ <li ng-class="selectedGroup._data.uuid === group._data.uuid ? 'selected' : ''" ng-repeat="group in groupsCollection._list" ng-click="selectGroup(group._data.uuid)">
+ <input
+ type="checkbox"
+ ng-value="group._data.uuid"
+ ng-checked="group.checked"
+ ng-model="group.checked"
+ >
+ <a href="javaScript:void(0)" >{{group.get('title')}}</a>
+ <br/>
+ <span ng-if="group.get('path')" class="label">Path:</span>/{{group.get('path')}}
+ </li>
+ </ul>
+
+
+ <div style="padding: 10px 5px 10px 5px">
+ <button class="btn btn-primary" ng-click="getPrevious()" style="display:{{previous_display}}">< Previous</button>
+ <button class="btn btn-primary" ng-click="getNext()" style="display:{{next_display}}; float:right;">Next ></button>
+ </div>
+
+ </div>
+
+ <div class="span9 tab-content" ng-show="selectedGroup.get" >
+ <div class="menu-toolbar">
+ <ul class="inline" >
+ <li class="tab" ng-class="currentGroupsPage.route === '/groups/details' ? 'selected' : ''"><a class="btn btn-primary toolbar" ng-click="selectGroupPage('/groups/details')"><i class="pictogram"></i>Details</a></li>
+ <li class="tab" ng-class="currentGroupsPage.route === '/groups/members' ? 'selected' : ''"><a class="btn btn-primary toolbar" ng-click="selectGroupPage('/groups/members')"><i class="pictogram">👥</i>Users</a></li>
+ <li class="tab" ng-class="currentGroupsPage.route === '/groups/activities' ? 'selected' : ''"><a class="btn btn-primary toolbar" ng-click="selectGroupPage('/groups/activities')"><i class="pictogram"></i>Activities</a></li>
+ <li class="tab" ng-class="currentGroupsPage.route === '/groups/roles' ? 'selected' : ''"><a class="btn btn-primary toolbar" ng-click="selectGroupPage('/groups/roles')"><i class="pictogram">🌎</i>Roles & Permissions</a></li>
+ </ul>
+ </div>
+ <span ng-include="currentGroupsPage.template"></span>
+
+ </section>
+</div>
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/508ef2f7/portal/js/lib/MD5.min.js
----------------------------------------------------------------------
diff --git a/portal/js/lib/MD5.min.js b/portal/js/lib/MD5.min.js
deleted file mode 100644
index 0bfc085..0000000
--- a/portal/js/lib/MD5.min.js
+++ /dev/null
@@ -1 +0,0 @@
-var MD5=function(a){function n(a){a=a.replace(/\r\n/g,"\n");var b="";for(var c=0;c<a.length;c++){var d=a.charCodeAt(c);if(d<128){b+=String.fromCharCode(d)}else if(d>127&&d<2048){b+=String.fromCharCode(d>>6|192);b+=String.fromCharCode(d&63|128)}else{b+=String.fromCharCode(d>>12|224);b+=String.fromCharCode(d>>6&63|128);b+=String.fromCharCode(d&63|128)}}return b}function m(a){var b="",c="",d,e;for(e=0;e<=3;e++){d=a>>>e*8&255;c="0"+d.toString(16);b=b+c.substr(c.length-2,2)}return b}function l(a){var b;var c=a.length;var d=c+8;var e=(d-d%64)/64;var f=(e+1)*16;var g=Array(f-1);var h=0;var i=0;while(i<c){b=(i-i%4)/4;h=i%4*8;g[b]=g[b]|a.charCodeAt(i)<<h;i++}b=(i-i%4)/4;h=i%4*8;g[b]=g[b]|128<<h;g[f-2]=c<<3;g[f-1]=c>>>29;return g}function k(a,d,e,f,h,i,j){a=c(a,c(c(g(d,e,f),h),j));return c(b(a,i),d)}function j(a,d,e,g,h,i,j){a=c(a,c(c(f(d,e,g),h),j));return c(b(a,i),d)}function i(a,d,f,g,h,i,j){a=c(a,c(c(e(d,f,g),h),j));return c(b(a,i),d)}function h(a,e,f,g,h,i,j){a=c(a,c(c(d(e,f,g),h),j));re
turn c(b(a,i),e)}function g(a,b,c){return b^(a|~c)}function f(a,b,c){return a^b^c}function e(a,b,c){return a&c|b&~c}function d(a,b,c){return a&b|~a&c}function c(a,b){var c,d,e,f,g;e=a&2147483648;f=b&2147483648;c=a&1073741824;d=b&1073741824;g=(a&1073741823)+(b&1073741823);if(c&d){return g^2147483648^e^f}if(c|d){if(g&1073741824){return g^3221225472^e^f}else{return g^1073741824^e^f}}else{return g^e^f}}function b(a,b){return a<<b|a>>>32-b}var o=Array();var p,q,r,s,t,u,v,w,x;var y=7,z=12,A=17,B=22;var C=5,D=9,E=14,F=20;var G=4,H=11,I=16,J=23;var K=6,L=10,M=15,N=21;a=n(a);o=l(a);u=1732584193;v=4023233417;w=2562383102;x=271733878;for(p=0;p<o.length;p+=16){q=u;r=v;s=w;t=x;u=h(u,v,w,x,o[p+0],y,3614090360);x=h(x,u,v,w,o[p+1],z,3905402710);w=h(w,x,u,v,o[p+2],A,606105819);v=h(v,w,x,u,o[p+3],B,3250441966);u=h(u,v,w,x,o[p+4],y,4118548399);x=h(x,u,v,w,o[p+5],z,1200080426);w=h(w,x,u,v,o[p+6],A,2821735955);v=h(v,w,x,u,o[p+7],B,4249261313);u=h(u,v,w,x,o[p+8],y,1770035416);x=h(x,u,v,w,o[p+9],z,2336552
879);w=h(w,x,u,v,o[p+10],A,4294925233);v=h(v,w,x,u,o[p+11],B,2304563134);u=h(u,v,w,x,o[p+12],y,1804603682);x=h(x,u,v,w,o[p+13],z,4254626195);w=h(w,x,u,v,o[p+14],A,2792965006);v=h(v,w,x,u,o[p+15],B,1236535329);u=i(u,v,w,x,o[p+1],C,4129170786);x=i(x,u,v,w,o[p+6],D,3225465664);w=i(w,x,u,v,o[p+11],E,643717713);v=i(v,w,x,u,o[p+0],F,3921069994);u=i(u,v,w,x,o[p+5],C,3593408605);x=i(x,u,v,w,o[p+10],D,38016083);w=i(w,x,u,v,o[p+15],E,3634488961);v=i(v,w,x,u,o[p+4],F,3889429448);u=i(u,v,w,x,o[p+9],C,568446438);x=i(x,u,v,w,o[p+14],D,3275163606);w=i(w,x,u,v,o[p+3],E,4107603335);v=i(v,w,x,u,o[p+8],F,1163531501);u=i(u,v,w,x,o[p+13],C,2850285829);x=i(x,u,v,w,o[p+2],D,4243563512);w=i(w,x,u,v,o[p+7],E,1735328473);v=i(v,w,x,u,o[p+12],F,2368359562);u=j(u,v,w,x,o[p+5],G,4294588738);x=j(x,u,v,w,o[p+8],H,2272392833);w=j(w,x,u,v,o[p+11],I,1839030562);v=j(v,w,x,u,o[p+14],J,4259657740);u=j(u,v,w,x,o[p+1],G,2763975236);x=j(x,u,v,w,o[p+4],H,1272893353);w=j(w,x,u,v,o[p+7],I,4139469664);v=j(v,w,x,u,o[p+10],J,320
0236656);u=j(u,v,w,x,o[p+13],G,681279174);x=j(x,u,v,w,o[p+0],H,3936430074);w=j(w,x,u,v,o[p+3],I,3572445317);v=j(v,w,x,u,o[p+6],J,76029189);u=j(u,v,w,x,o[p+9],G,3654602809);x=j(x,u,v,w,o[p+12],H,3873151461);w=j(w,x,u,v,o[p+15],I,530742520);v=j(v,w,x,u,o[p+2],J,3299628645);u=k(u,v,w,x,o[p+0],K,4096336452);x=k(x,u,v,w,o[p+7],L,1126891415);w=k(w,x,u,v,o[p+14],M,2878612391);v=k(v,w,x,u,o[p+5],N,4237533241);u=k(u,v,w,x,o[p+12],K,1700485571);x=k(x,u,v,w,o[p+3],L,2399980690);w=k(w,x,u,v,o[p+10],M,4293915773);v=k(v,w,x,u,o[p+1],N,2240044497);u=k(u,v,w,x,o[p+8],K,1873313359);x=k(x,u,v,w,o[p+15],L,4264355552);w=k(w,x,u,v,o[p+6],M,2734768916);v=k(v,w,x,u,o[p+13],N,1309151649);u=k(u,v,w,x,o[p+4],K,4149444226);x=k(x,u,v,w,o[p+11],L,3174756917);w=k(w,x,u,v,o[p+2],M,718787259);v=k(v,w,x,u,o[p+9],N,3951481745);u=c(u,q);v=c(v,r);w=c(w,s);x=c(x,t)}var O=m(u)+m(v)+m(w)+m(x);return O.toLowerCase()}
\ No newline at end of file