diff --git a/common/browserify.js b/common/browserify.js
index 0530144839..3653cb81b0 100644
--- a/common/browserify.js
+++ b/common/browserify.js
@@ -1,3 +1,5 @@
+require('babel-polyfill');
+
var shared = require('./script/index');
var _ = require('lodash');
var moment = require('moment');
diff --git a/common/script/public/config.js b/common/script/public/config.js
index bb78e244bd..53e5f19091 100644
--- a/common/script/public/config.js
+++ b/common/script/public/config.js
@@ -1,5 +1,7 @@
'use strict';
-angular.module('habitrpg').config(['$httpProvider', function($httpProvider){
+
+angular.module('habitrpg')
+.config(['$httpProvider', function($httpProvider){
$httpProvider.interceptors.push(['$q', '$rootScope', function($q, $rootScope){
return {
response: function(response) {
@@ -28,15 +30,15 @@ angular.module('habitrpg').config(['$httpProvider', function($httpProvider){
// 400 range?
} else if (response.status < 500) {
- $rootScope.$broadcast('responseText', response.data.err || response.data);
+ $rootScope.$broadcast('responseText', response.data.err || response.data.message);
// Need to reject the prompse so the error is handled correctly
- if (response.status === 401)
+ if (response.status === 401) {
return $q.reject(response);
-
+ }
// Error
} else {
- var error = window.env.t('requestError') + '
"' +
- window.env.t('error') + ' ' + (response.data.err || response.data || 'something went wrong') +
+ var error = window.env.t('requestError') + '
"' +
+ window.env.t('error') + ' ' + (response.data.err || response.data || 'something went wrong') +
'"
' + window.env.t('seeConsole');
if (mobileApp) error = 'Error contacting the server. Please try again in a few minutes.';
$rootScope.$broadcast('responseError', error);
@@ -47,4 +49,4 @@ angular.module('habitrpg').config(['$httpProvider', function($httpProvider){
}
};
}]);
-}]);
\ No newline at end of file
+}]);
diff --git a/common/script/public/userServices.js b/common/script/public/userServices.js
index e5b1790086..4fb92ce42a 100644
--- a/common/script/public/userServices.js
+++ b/common/script/public/userServices.js
@@ -102,14 +102,14 @@ angular.module('habitrpg')
op(req,function(err,response) {
for(var updatedItem in req.body) {
var itemUpdateResponse = userNotifications[updatedItem];
- if(itemUpdateResponse) Notification.text(itemUpdateResponse);
+ if(itemUpdateResponse) Notification.text(itemUpdateResponse.data.message);
}
if (err) {
- var message = err.code ? err.message : err;
- if (MOBILE_APP) Notification.push({type:'text',text:message});
+ var message = err.code ? err.data.message : err;
+ if (MOBILE_APP) Notification.push({type:'text', text: message});
else Notification.text(message);
// In the case of 200s, they're friendly alert messages like "Your pet has hatched!" - still send the op
- if ((err.code && err.code >= 400) || !err.code) return;
+ if ((err.code && err.code >= 400) || !err.code) return;
}
userServices.log({op:k, params: req.params, query:req.query, body:req.body});
});
diff --git a/test/spec/controllers/groupCtrlSpec.js b/test/spec/controllers/groupCtrlSpec.js
index dce054bef6..da00e2ba73 100644
--- a/test/spec/controllers/groupCtrlSpec.js
+++ b/test/spec/controllers/groupCtrlSpec.js
@@ -23,6 +23,53 @@ describe('Groups Controller', function() {
});
});
+ describe("isMemberOfPendingQuest", function() {
+ var party;
+ var partyStub;
+
+ beforeEach(function () {
+ party = specHelper.newGroup({
+ _id: "unique-party-id",
+ type: 'party',
+ members: ['leader-id'] // Ensure we wouldn't pass automatically.
+ });
+
+ partyStub = sandbox.stub(groups, "party", function() {
+ return party;
+ });
+ });
+
+ it("returns false if group is does not have a quest", function() {
+ expect(scope.isMemberOfPendingQuest(user._id, party)).to.not.be.ok;
+ });
+
+ it("returns false if group quest has not members", function() {
+ party.quest = {
+ 'key': 'random-key',
+ };
+ expect(scope.isMemberOfPendingQuest(user._id, party)).to.not.be.ok;
+ });
+
+ it("returns false if group quest is active", function() {
+ party.quest = {
+ 'key': 'random-key',
+ 'members': {},
+ 'active': true,
+ };
+ party.quest.members[user._id] = true;
+ expect(scope.isMemberOfPendingQuest(user._id, party)).to.not.be.ok;
+ });
+
+ it("returns true if user is a member of a pending quest", function() {
+ party.quest = {
+ 'key': 'random-key',
+ 'members': {},
+ };
+ party.quest.members[user._id] = true;
+ expect(scope.isMemberOfPendingQuest(user._id, party)).to.be.ok;
+ });
+ });
+
describe("isMemberOfGroup", function() {
it("returns true if group is the user's party retrieved from groups service", function() {
var party = specHelper.newGroup({
@@ -31,7 +78,7 @@ describe('Groups Controller', function() {
members: ['leader-id'] // Ensure we wouldn't pass automatically.
});
- var partyStub = sandbox.stub(groups,"party", function() {
+ var partyStub = sandbox.stub(groups, "party", function() {
return party;
});
@@ -46,7 +93,7 @@ describe('Groups Controller', function() {
members: [user._id]
});
- var myGuilds = sandbox.stub(groups,"myGuilds", function() {
+ var myGuilds = sandbox.stub(groups, "myGuilds", function() {
return [guild];
});
diff --git a/test/spec/controllers/partyCtrlSpec.js b/test/spec/controllers/partyCtrlSpec.js
index 92401f1987..623d63a74e 100644
--- a/test/spec/controllers/partyCtrlSpec.js
+++ b/test/spec/controllers/partyCtrlSpec.js
@@ -2,6 +2,7 @@
describe("Party Controller", function() {
var scope, ctrl, user, User, questsService, groups, rootScope, $controller;
+ var party;
beforeEach(function() {
user = specHelper.newUser(),
@@ -10,7 +11,13 @@ describe("Party Controller", function() {
user: user,
sync: sandbox.spy(),
set: sandbox.spy()
- }
+ };
+
+ party = specHelper.newGroup({
+ _id: "unique-party-id",
+ type: 'party',
+ members: ['leader-id'] // Ensure we wouldn't pass automatically.
+ });
module(function($provide) {
$provide.value('User', User);
@@ -136,6 +143,25 @@ describe("Party Controller", function() {
});
});
+ describe("create", function() {
+ var partyStub;
+
+ beforeEach(function () {
+ partyStub = sandbox.stub(groups.Group, "create", function() {
+ return party;
+ });
+ });
+
+ it("creates a new party", function() {
+ var group = {
+ type: 'party',
+ };
+ scope.create(group);
+ expect(partyStub).to.be.calledOnce;
+ //@TODO: Check user party console.log(User.user.party.id)
+ });
+ });
+
describe('questAccept', function() {
beforeEach(function() {
scope.group = {
diff --git a/test/spec/services/groupServicesSpec.js b/test/spec/services/groupServicesSpec.js
index e9a9285265..065af0b233 100644
--- a/test/spec/services/groupServicesSpec.js
+++ b/test/spec/services/groupServicesSpec.js
@@ -2,6 +2,7 @@
describe('groupServices', function() {
var $httpBackend, $http, groups, user;
+ var groupApiUrlPrefix = '/api/v3/groups';
beforeEach(function() {
module(function($provide) {
@@ -16,27 +17,141 @@ describe('groupServices', function() {
});
});
+ it('calls get groups', function() {
+ $httpBackend.expectGET(groupApiUrlPrefix).respond({});
+ groups.Group.getGroups();
+ $httpBackend.flush();
+ });
+
+ it('calls get group', function() {
+ var gid = 1;
+ $httpBackend.expectGET(groupApiUrlPrefix + '/' + gid).respond({});
+ groups.Group.get(gid);
+ $httpBackend.flush();
+ });
+
it('calls party endpoint', function() {
- $httpBackend.expectGET('/api/v2/groups/party').respond({});
+ $httpBackend.expectGET(groupApiUrlPrefix + '/party').respond({});
+ groups.Group.syncParty();
+ $httpBackend.flush();
+ });
+
+ it('calls create endpoint', function() {
+ $httpBackend.expectPOST(groupApiUrlPrefix).respond({});
+ groups.Group.create({});
+ $httpBackend.flush();
+ });
+
+ it('calls update group', function() {
+ var gid = 1;
+ var groupDetails = { _id: gid };
+ $httpBackend.expectPUT(groupApiUrlPrefix + '/' + gid).respond({});
+ groups.Group.update(groupDetails);
+ $httpBackend.flush();
+ });
+
+ it('calls join group', function() {
+ var gid = 1;
+ $httpBackend.expectPOST(groupApiUrlPrefix + '/' + gid + '/join').respond({});
+ groups.Group.join(gid);
+ $httpBackend.flush();
+ });
+
+ it('calls reject invite group', function() {
+ var gid = 1;
+ $httpBackend.expectPOST(groupApiUrlPrefix + '/' + gid + '/reject-invite').respond({});
+ groups.Group.rejectInvite(gid);
+ $httpBackend.flush();
+ });
+
+ it('calls invite group', function() {
+ var gid = 1;
+ $httpBackend.expectPOST(groupApiUrlPrefix + '/' + gid + '/invite').respond({});
+ groups.Group.invite(gid, [], []);
+ $httpBackend.flush();
+ });
+
+ it('calls party endpoint when party is not cached', function() {
+ $httpBackend.expectGET(groupApiUrlPrefix + '/party').respond({});
groups.party();
$httpBackend.flush();
});
- it('calls tavern endpoint', function() {
- $httpBackend.expectGET('/api/v2/groups/habitrpg').respond({});
+ it('returns party if cached', function (done) {
+ var uid = 'abc';
+ var party = {
+ _id: uid,
+ };
+ groups.data.party = party;
+ groups.party()
+ .then(function (result) {
+ expect(result).to.eql(party);
+ done();
+ });
+ $httpBackend.flush();
+ });
+
+ it('calls tavern endpoint when tavern is not cached', function() {
+ $httpBackend.expectGET(groupApiUrlPrefix + '/habitrpg').respond({});
groups.tavern();
$httpBackend.flush();
});
+ it('returns tavern if cached', function (done) {
+ var uid = 'abc';
+ var tavern = {
+ _id: uid,
+ };
+ groups.data.tavern = tavern;
+ groups.tavern()
+ .then(function (result) {
+ expect(result).to.eql(tavern);
+ done();
+ });
+ $httpBackend.flush();
+ });
+
it('calls public guilds endpoint', function() {
- $httpBackend.expectGET('/api/v2/groups?type=public').respond([]);
+ $httpBackend.expectGET(groupApiUrlPrefix + '?type=publicGuilds').respond([]);
groups.publicGuilds();
$httpBackend.flush();
});
+ it('returns public guilds if cached', function (done) {
+ var uid = 'abc';
+ var publicGuilds = [
+ {_id: uid},
+ ];
+ groups.data.publicGuilds = publicGuilds;
+
+ groups.publicGuilds()
+ .then(function (result) {
+ expect(result).to.eql(publicGuilds);
+ done();
+ });
+
+ $httpBackend.flush();
+ });
+
it('calls my guilds endpoint', function() {
- $httpBackend.expectGET('/api/v2/groups?type=guilds').respond([]);
+ $httpBackend.expectGET(groupApiUrlPrefix + '?type=privateGuilds').respond([]);
groups.myGuilds();
$httpBackend.flush();
});
+
+ it('returns my guilds if cached', function (done) {
+ var uid = 'abc';
+ var myGuilds = [
+ {_id: uid},
+ ];
+ groups.data.myGuilds = myGuilds;
+
+ groups.myGuilds()
+ .then(function (myGuilds) {
+ expect(myGuilds).to.eql(myGuilds);
+ done();
+ });
+
+ $httpBackend.flush();
+ });
});
diff --git a/test/spec/specHelper.js b/test/spec/specHelper.js
index 9324fa5d8b..cbacac1988 100644
--- a/test/spec/specHelper.js
+++ b/test/spec/specHelper.js
@@ -28,6 +28,9 @@ var specHelper = {};
var user = {
_id: 'unique-user-id',
+ profile: {
+ name: 'dummy-name',
+ },
auth: { timestamps: {} },
stats: stats,
items: items,
diff --git a/website/public/js/app.js b/website/public/js/app.js
index 6b39f45d63..67215bc810 100644
--- a/website/public/js/app.js
+++ b/website/public/js/app.js
@@ -152,10 +152,11 @@ window.habitrpg = angular.module('habitrpg',
title: env.t('titleGuilds'),
controller: ['$scope', 'Groups', 'Chat', '$stateParams',
function($scope, Groups, Chat, $stateParams){
- Groups.Group.get({gid:$stateParams.gid}, function(group){
- $scope.group = group;
- Chat.seenMessage(group._id);
- });
+ Groups.Group.get($stateParams.gid)
+ .then(function (response) {
+ $scope.group = response.data.data;
+ Chat.seenMessage($scope.group._id);
+ });
}]
})
diff --git a/website/public/js/controllers/groupsCtrl.js b/website/public/js/controllers/groupsCtrl.js
index e7865afb55..224efc6fdb 100644
--- a/website/public/js/controllers/groupsCtrl.js
+++ b/website/public/js/controllers/groupsCtrl.js
@@ -3,24 +3,24 @@
habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', '$http', '$q', 'User', 'Members', '$state', 'Notification',
function($scope, $rootScope, Shared, Groups, $http, $q, User, Members, $state, Notification) {
- $scope.isMemberOfPendingQuest = function(userid, group) {
+ $scope.isMemberOfPendingQuest = function (userid, group) {
if (!group.quest || !group.quest.members) return false;
if (group.quest.active) return false; // quest is started, not pending
return userid in group.quest.members && group.quest.members[userid] != false;
};
- $scope.isMemberOfRunningQuest = function(userid, group) {
+ $scope.isMemberOfRunningQuest = function (userid, group) {
if (!group.quest || !group.quest.members) return false;
if (!group.quest.active) return false; // quest is pending, not started
return group.quest.members[userid];
};
- $scope.isMemberOfGroup = function(userid, group){
-
+ $scope.isMemberOfGroup = function (userid, group) {
// If the group is a guild, just check for an intersection with the
// current user's guilds, rather than checking the members of the group.
if(group.type === 'guild') {
- return _.detect(Groups.myGuilds(), function(g) { return g._id === group._id });
+ var guilds = Groups.myGuilds();
+ return _.detect(guilds, function(g) { return g._id === group._id });
}
// Similarly, if we're dealing with the user's current party, return true.
@@ -34,7 +34,7 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', '
return ~(memberIds.indexOf(userid));
};
- $scope.isMember = function(user, group){
+ $scope.isMember = function (user, group) {
return ~(group.members.indexOf(user._id));
};
@@ -47,7 +47,6 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', '
group._editing = true;
};
-
$scope.saveEdit = function (group) {
var newLeader = $scope.groupCopy._newLeader && $scope.groupCopy._newLeader._id;
@@ -57,7 +56,7 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', '
angular.copy($scope.groupCopy, group);
- group.$save();
+ Groups.Group.update(group);
$scope.cancelEdit(group);
};
@@ -91,7 +90,6 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', '
}
};
-
$scope.removeMember = function(group, member, isMember){
// TODO find a better way to do this (share data with remove member modal)
$scope.removeMemberData = {
@@ -103,12 +101,12 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', '
};
$scope.confirmRemoveMember = function(confirm){
- if(confirm){
- Groups.Group.removeMember({
- gid: $scope.removeMemberData.group._id,
- uuid: $scope.removeMemberData.member._id,
- message: $scope.removeMemberData.message,
- }, undefined, function(){
+ if (confirm) {
+ Groups.Group.removeMember(
+ $scope.removeMemberData.group._id,
+ $scope.removeMemberData.member._id,
+ $scope.removeMemberData.message
+ ).then(function (response) {
if($scope.removeMemberData.isMember){
_.pull($scope.removeMemberData.group.members, $scope.removeMemberData.member);
}else{
@@ -117,7 +115,7 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', '
$scope.removeMemberData = undefined;
});
- }else{
+ } else {
$scope.removeMemberData = undefined;
}
};
@@ -141,5 +139,4 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', '
$rootScope.openModal('private-message',{controller:'MemberModalCtrl'});
});
}
-
}]);
diff --git a/website/public/js/controllers/guildsCtrl.js b/website/public/js/controllers/guildsCtrl.js
index df6b001448..70493071c0 100644
--- a/website/public/js/controllers/guildsCtrl.js
+++ b/website/public/js/controllers/guildsCtrl.js
@@ -4,41 +4,71 @@ habitrpg.controller("GuildsCtrl", ['$scope', 'Groups', 'User', 'Challenges', '$r
function($scope, Groups, User, Challenges, $rootScope, $state, $location, $compile, Analytics) {
$scope.groups = {
guilds: Groups.myGuilds(),
- "public": Groups.publicGuilds()
- }
+ public: Groups.publicGuilds(),
+ };
+
+ Groups.myGuilds()
+ .then(function (guilds) {
+ $scope.groups.guilds = guilds;
+ });
+
+ Groups.publicGuilds()
+ .then(function (guilds) {
+ $scope.groups.public = guilds;
+ });
+
$scope.type = 'guild';
$scope.text = window.env.t('guild');
+
var newGroup = function(){
- return new Groups.Group({type:'guild', privacy:'private'});
+ return {type:'guild', privacy:'private'};
}
$scope.newGroup = newGroup()
+
$scope.create = function(group){
- if (User.user.balance < 1)
+ if (User.user.balance < 1) {
return $rootScope.openModal('buyGems', {track:"Gems > Create Group"});
+ }
if (confirm(window.env.t('confirmGuild'))) {
- group.$save(function(saved){
- if (saved.privacy == 'public') {Analytics.track({'hitType':'event','eventCategory':'behavior','eventAction':'join group','owner':true,'groupType':'guild','privacy':saved.privacy,'groupName':saved.name})}
- else {Analytics.track({'hitType':'event','eventCategory':'behavior','eventAction':'join group','owner':true,'groupType':'guild','privacy':saved.privacy})}
- $rootScope.hardRedirect('/#/options/groups/guilds/' + saved._id);
- });
+ Groups.Group.create(group)
+ .then(function (response) {
+ var createdGroup = response.data.data;
+ if (createdGroup.privacy == 'public') {
+ Analytics.track({'hitType':'event', 'eventCategory':'behavior', 'eventAction':'join group', 'owner':true, 'groupType':'guild', 'privacy': createdGroup.privacy, 'groupName':createdGroup.name})
+ } else {
+ Analytics.track({'hitType':'event', 'eventCategory':'behavior', 'eventAction':'join group', 'owner':true, 'groupType':'guild', 'privacy': createdGroup.privacy})
+ }
+ $rootScope.hardRedirect('/#/options/groups/guilds/' + createdGroup._id);
+ });
}
}
- $scope.join = function(group){
- // If we're accepting an invitation, we don't have the actual group object, but a faux group object (for performance
- // purposes) {id, name}. Let's trick ngResource into thinking we have a group, so we can call the same $join
- // function (server calls .attachGroup(), which finds group by _id and handles this properly)
+ $scope.join = function (group) {
+ var groupId = group._id;
+
+ // If we don't have the _id property, we are joining from an invitation
+ // which contains a id property of the group
if (group.id && !group._id) {
- group = new Groups.Group({_id:group.id});
+ groupId = group.id;
}
- group.$join(function(joined){
- if (joined.privacy == 'public') {Analytics.track({'hitType':'event','eventCategory':'behavior','eventAction':'join group','owner':false,'groupType':'guild','privacy':joined.privacy,'groupName':joined.name})}
- else {Analytics.track({'hitType':'event','eventCategory':'behavior','eventAction':'join group','owner':false,'groupType':'guild','privacy':joined.privacy})}
- $rootScope.hardRedirect('/#/options/groups/guilds/' + joined._id);
- })
+ Groups.Group.join(groupId)
+ .then(function (response) {
+ var joinedGroup = response.data.data;
+
+ if (joinedGroup.privacy == 'public') {
+ Analytics.track({'hitType':'event', 'eventCategory':'behavior', 'eventAction':'join group', 'owner':false, 'groupType':'guild','privacy': joinedGroup.privacy, 'groupName': joinedGroup.name})
+ } else {
+ Analytics.track({'hitType':'event', 'eventCategory':'behavior', 'eventAction':'join group', 'owner':false, 'groupType':'guild','privacy': joinedGroup.privacy})
+ }
+ $rootScope.hardRedirect('/#/options/groups/guilds/' + joinedGroup._id);
+ });
+ }
+
+ $scope.reject = function(guild) {
+ Groups.Group.rejectInvite(guild.id);
}
$scope.leave = function(keep) {
@@ -46,49 +76,44 @@ habitrpg.controller("GuildsCtrl", ['$scope', 'Groups', 'User', 'Challenges', '$r
$scope.selectedGroup = undefined;
$scope.popoverEl.popover('destroy');
} else {
- Groups.Group.leave({gid: $scope.selectedGroup._id, keep:keep}, undefined, function(){
+ Groups.Group.leave($scope.selectedGroup._id, keep)
+ .success(function (data) {
$rootScope.hardRedirect('/#/options/groups/guilds');
- });
+ });
}
}
$scope.clickLeave = function(group, $event){
- $scope.selectedGroup = group;
- $scope.popoverEl = $($event.target).closest('.btn');
- var html, title;
- Challenges.Challenge.query(function(challenges) {
- challenges = _.pluck(_.filter(challenges, function(c) {
- return c.group._id == group._id;
- }), '_id');
+ $scope.selectedGroup = group;
+ $scope.popoverEl = $($event.target).closest('.btn');
- if (_.intersection(challenges, User.user.challenges).length > 0) {
- html = $compile(
- '' + window.env.t('removeTasks') + '
\n' + window.env.t('keepTasks') + '
\n' + window.env.t('cancel') + '
'
- )($scope);
- title = window.env.t('leaveGroupCha');
- } else {
- html = $compile(
- '' + window.env.t('confirm') + '
\n' + window.env.t('cancel') + '
'
- )($scope);
- title = window.env.t('leaveGroup')
- }
+ var html, title;
- $scope.popoverEl.popover('destroy').popover({
- html: true,
- placement: 'top',
- trigger: 'manual',
- title: title,
- content: html
- }).popover('show');
- });
- }
+ Challenges.Challenge.query(function(challenges) {
+ challenges = _.pluck(_.filter(challenges, function(c) {
+ return c.group._id == group._id;
+ }), '_id');
- $scope.reject = function(guild){
- var i = _.findIndex(User.user.invitations.guilds, {id:guild.id});
- if (~i){
- User.user.invitations.guilds.splice(i, 1);
- User.set({'invitations.guilds':User.user.invitations.guilds});
- }
+ if (_.intersection(challenges, User.user.challenges).length > 0) {
+ html = $compile(
+ '' + window.env.t('removeTasks') + '
\n' + window.env.t('keepTasks') + '
\n' + window.env.t('cancel') + '
'
+ )($scope);
+ title = window.env.t('leaveGroupCha');
+ } else {
+ html = $compile(
+ '' + window.env.t('confirm') + '
\n' + window.env.t('cancel') + '
'
+ )($scope);
+ title = window.env.t('leaveGroup')
+ }
+
+ $scope.popoverEl.popover('destroy').popover({
+ html: true,
+ placement: 'top',
+ trigger: 'manual',
+ title: title,
+ content: html
+ }).popover('show');
+ });
}
}
]);
diff --git a/website/public/js/controllers/inviteToGroupCtrl.js b/website/public/js/controllers/inviteToGroupCtrl.js
index f4a74dbac9..ca155d8b98 100644
--- a/website/public/js/controllers/inviteToGroupCtrl.js
+++ b/website/public/js/controllers/inviteToGroupCtrl.js
@@ -1,6 +1,7 @@
'use strict';
-habitrpg.controller('InviteToGroupCtrl', ['$scope', 'User', 'Groups', 'injectedGroup', '$http', 'Notification', function($scope, User, Groups, injectedGroup, $http, Notification) {
+habitrpg.controller('InviteToGroupCtrl', ['$scope', 'User', 'Groups', 'injectedGroup', '$http', 'Notification',
+ function($scope, User, Groups, injectedGroup, $http, Notification) {
$scope.group = injectedGroup;
$scope.inviter = User.user.profile.name;
@@ -17,8 +18,9 @@ habitrpg.controller('InviteToGroupCtrl', ['$scope', 'User', 'Groups', 'injectedG
$scope.inviteNewUsers = function(inviteMethod) {
if (!$scope.group._id) {
$scope.group.name = $scope.group.name || env.t('possessiveParty', {name: User.user.profile.name});
- return $scope.group.$save()
- .then(function(res) {
+ return Groups.Group.create($scope.group)
+ .then(function(response) {
+ $scope.group = response.data.data;
_inviteByMethod(inviteMethod);
});
}
@@ -39,12 +41,13 @@ habitrpg.controller('InviteToGroupCtrl', ['$scope', 'User', 'Groups', 'injectedG
return console.log('Invalid invite method.')
}
- Groups.Group.invite({gid: $scope.group._id}, invitationDetails, function(){
- Notification.text(window.env.t('invitationsSent'));
- _resetInvitees();
- }, function(){
- _resetInvitees();
- });
+ Groups.Group.invite($scope.group._id, invitationDetails)
+ .then(function() {
+ Notification.text(window.env.t('invitationsSent'));
+ _resetInvitees();
+ }, function(){
+ _resetInvitees();
+ });
}
function _getOnlyUuids() {
diff --git a/website/public/js/controllers/partyCtrl.js b/website/public/js/controllers/partyCtrl.js
index 6494679911..022d4044a7 100644
--- a/website/public/js/controllers/partyCtrl.js
+++ b/website/public/js/controllers/partyCtrl.js
@@ -1,20 +1,36 @@
'use strict';
habitrpg.controller("PartyCtrl", ['$rootScope','$scope','Groups','Chat','User','Challenges','$state','$compile','Analytics','Quests','Social',
- function($rootScope,$scope,Groups,Chat,User,Challenges,$state,$compile,Analytics,Quests,Social) {
+ function($rootScope, $scope, Groups, Chat, User, Challenges, $state, $compile, Analytics, Quests, Social) {
var user = User.user;
$scope.type = 'party';
$scope.text = window.env.t('party');
- $scope.group = $rootScope.party = Groups.party();
- $scope.newGroup = new Groups.Group({type:'party'});
+
+ //@TODO: cache
+ Groups.Group.syncParty()
+ .then(function successCallback(response) {
+ $scope.group = response.data.data;
+ checkForNotifications();
+ }, function errorCallback(response) {
+ $scope.newGroup = $scope.group = { type: 'party' };
+ });
+
$scope.inviteOrStartParty = Groups.inviteOrStartParty;
$scope.loadWidgets = Social.loadWidgets;
if ($state.is('options.social.party')) {
- $scope.group.$syncParty(); // Sync party automatically when navigating to party page
-
+ Groups.Group.syncParty()
+ .then(function successCallback(response) {
+ $scope.group = response.data.data;
+ checkForNotifications();
+ }, function errorCallback(response) {
+ $scope.newGroup = { type: 'party' };
+ });
+ }
+ // Chat.seenMessage($scope.group._id);
+ function checkForNotifications () {
// Checks if user's party has reached 2 players for the first time.
if(!user.achievements.partyUp
&& $scope.group.memberCount >= 2) {
@@ -30,36 +46,35 @@ habitrpg.controller("PartyCtrl", ['$rootScope','$scope','Groups','Chat','User','
}
}
- Chat.seenMessage($scope.group._id);
-
- $scope.create = function(group){
+ $scope.create = function (group) {
if (!group.name) group.name = env.t('possessiveParty', {name: User.user.profile.name});
- group.$save(function(){
- Analytics.track({'hitType':'event','eventCategory':'behavior','eventAction':'join group','owner':true,'groupType':'party','privacy':'private'});
- Analytics.updateUser({'partyID':group.id,'partySize':1});
+ Groups.Group.create(group, function() {
+ Analytics.track({'hitType':'event', 'eventCategory':'behavior', 'eventAction':'join group', 'owner':true, 'groupType':'party', 'privacy':'private'});
+ Analytics.updateUser({'party.id': group.id, 'partySize': 1});
$rootScope.hardRedirect('/#/options/groups/party');
});
};
- $scope.join = function(party){
- var group = new Groups.Group({_id: party.id, name: party.name});
- group.$join(function(){
- Analytics.track({'hitType':'event','eventCategory':'behavior','eventAction':'join group','owner':false,'groupType':'party','privacy':'private'});
- Analytics.updateUser({'partyID':party.id});
- $rootScope.hardRedirect('/#/options/groups/party');
- });
+ $scope.join = function (party) {
+ Groups.Group.join(party.id)
+ .then(function (response) {
+ Analytics.track({'hitType':'event','eventCategory':'behavior','eventAction':'join group','owner':false,'groupType':'party','privacy':'private'});
+ Analytics.updateUser({'partyID': party.id});
+ $rootScope.hardRedirect('/#/options/groups/party');
+ });
};
// TODO: refactor guild and party leave into one function
- $scope.leave = function(keep) {
+ $scope.leave = function (keep) {
if (keep == 'cancel') {
$scope.selectedGroup = undefined;
$scope.popoverEl.popover('destroy');
} else {
- Groups.Group.leave({gid: $scope.selectedGroup._id, keep:keep}, undefined, function(){
- Analytics.updateUser({'partySize':null,'partyID':null});
- $rootScope.hardRedirect('/#/options/groups/party');
- });
+ Groups.Group.leave($scope.selectedGroup._id, keep)
+ .then(function (response) {
+ Analytics.updateUser({'partySize':null,'partyID':null});
+ $rootScope.hardRedirect('/#/options/groups/party');
+ });
}
};
@@ -69,21 +84,27 @@ habitrpg.controller("PartyCtrl", ['$rootScope','$scope','Groups','Chat','User','
$scope.selectedGroup = group;
$scope.popoverEl = $($event.target).closest('.btn');
var html, title;
- Challenges.Challenge.query(function(challenges) {
- challenges = _.pluck(_.filter(challenges, function(c) {
- return c.group._id == group._id;
- }), '_id');
- if (_.intersection(challenges, User.user.challenges).length > 0) {
- html = $compile(
- '' + window.env.t('removeTasks') + '
\n' + window.env.t('keepTasks') + '
\n' + window.env.t('cancel') + '
'
- )($scope);
- title = window.env.t('leavePartyCha');
- } else {
- html = $compile(
- '' + window.env.t('confirm') + '
\n' + window.env.t('cancel') + '
'
- )($scope);
- title = window.env.t('leaveParty');
- }
+ html = $compile('' + window.env.t('removeTasks') + '
\n' + window.env.t('keepTasks') + '
\n' + window.env.t('cancel') + '
')($scope);
+ title = window.env.t('leavePartyCha');
+
+ //TODO: Move this to challenge service
+ //@TODO: Implement this when we convert front-end challenge service
+ // Challenges.Challenge.query(function(challenges) {
+ // challenges = _.pluck(_.filter(challenges, function(c) {
+ // return c.group._id == group._id;
+ // }), '_id');
+ // if (_.intersection(challenges, User.user.challenges).length > 0) {
+ // html = $compile(
+ // '' + window.env.t('removeTasks') + '
\n' + window.env.t('keepTasks') + '
\n' + window.env.t('cancel') + '
'
+ // )($scope);
+ // title = window.env.t('leavePartyCha');
+ // } else {
+ // html = $compile(
+ // '' + window.env.t('confirm') + '
\n' + window.env.t('cancel') + '
'
+ // )($scope);
+ // title = window.env.t('leaveParty');
+ // }
+
$scope.popoverEl.popover('destroy').popover({
html: true,
placement: 'top',
@@ -91,10 +112,10 @@ habitrpg.controller("PartyCtrl", ['$rootScope','$scope','Groups','Chat','User','
title: title,
content: html
}).popover('show');
- });
+ // });
};
- $scope.clickStartQuest = function(){
+ $scope.clickStartQuest = function () {
Analytics.track({'hitType':'event','eventCategory':'button','eventAction':'click','eventLabel':'Start a Quest'});
var hasQuests = _.find(User.user.items.quests, function(quest) {
return quest > 0;
@@ -109,7 +130,7 @@ habitrpg.controller("PartyCtrl", ['$rootScope','$scope','Groups','Chat','User','
$scope.leaveOldPartyAndJoinNewParty = function(newPartyId, newPartyName) {
if (confirm('Are you sure you want to delete your party and join ' + newPartyName + '?')) {
- Groups.Group.leave({gid: Groups.party()._id, keep:false}, undefined, function() {
+ Groups.Group.leave({gid: Groups.party()._id, keep: false}, undefined, function() {
$scope.group = {
loadingNewParty: true
};
@@ -118,7 +139,8 @@ habitrpg.controller("PartyCtrl", ['$rootScope','$scope','Groups','Chat','User','
}
}
- $scope.reject = function(){
+ $scope.reject = function(party) {
+ Groups.Group.rejectInvite(party.id);
User.set({'invitations.party':{}});
}
diff --git a/website/public/js/services/groupServices.js b/website/public/js/services/groupServices.js
index 001a137d63..e208b5bbdf 100644
--- a/website/public/js/services/groupServices.js
+++ b/website/public/js/services/groupServices.js
@@ -1,80 +1,191 @@
'use strict';
-(function() {
- angular
- .module('habitrpg')
- .factory('Groups', groupsFactory);
+angular.module('habitrpg')
+.factory('Groups', [ '$location', '$rootScope', '$http', 'Analytics', 'ApiUrl', 'Challenges', 'User', '$q',
+ function($location, $rootScope, $http, Analytics, ApiUrl, Challenges, User, $q) {
+ var data = {party: undefined, myGuilds: undefined, publicGuilds: undefined, tavern: undefined };
+ var groupApiURLPrefix = "/api/v3/groups";
- groupsFactory.$inject = [
- '$location',
- '$resource',
- '$rootScope',
- 'Analytics',
- 'ApiUrl',
- 'Challenges',
- 'User'
- ];
+ var Group = {};
- function groupsFactory($location, $resource, $rootScope, Analytics, ApiUrl, Challenges, User) {
+ //@TODO: Add paging
+ Group.getGroups = function(type) {
+ var url = groupApiURLPrefix;
+ if (type) {
+ url += '?type=' + type;
+ }
- var data = {party: undefined, myGuilds: undefined, publicGuilds: undefined, tavern: undefined};
- var Group = $resource(ApiUrl.get() + '/api/v2/groups/:gid',
- {gid:'@_id', messageId: '@_messageId'},
- {
- get: {
- method: "GET",
- isArray:false,
- // Wrap challenges as ngResource so they have functions like $leave or $join
- transformResponse: function(data) {
- data = angular.fromJson(data);
- _.each(data && data.challenges, function(c) {
- angular.extend(c, Challenges.Challenge.prototype);
- });
- return data;
- }
- },
-
- syncParty: {method: "GET", url: '/api/v2/groups/party'},
- join: {method: "POST", url: ApiUrl.get() + '/api/v2/groups/:gid/join'},
- leave: {method: "POST", url: ApiUrl.get() + '/api/v2/groups/:gid/leave'},
- invite: {method: "POST", url: ApiUrl.get() + '/api/v2/groups/:gid/invite'},
- removeMember: {method: "POST", url: ApiUrl.get() + '/api/v2/groups/:gid/removeMember'},
- startQuest: {method: "POST", url: ApiUrl.get() + '/api/v2/groups/:gid/questAccept'}
+ return $http({
+ method: 'GET',
+ url: url,
});
+ };
- function party(cb) {
- if (!data.party) return (data.party = Group.get({gid: 'party'}, cb));
- return (cb) ? cb(party) : data.party;
+ Group.get = function(gid) {
+ return $http({
+ method: 'GET',
+ url: groupApiURLPrefix + '/' + gid,
+ });
+ };
+
+ Group.syncParty = function() {
+ return this.get('party');
+ };
+
+ Group.create = function(groupDetails) {
+ return $http({
+ method: "POST",
+ url: groupApiURLPrefix,
+ data: groupDetails,
+ });
+ };
+
+ Group.update = function(groupDetails) {
+ //@TODO: Check for what has changed?
+ return $http({
+ method: "PUT",
+ url: groupApiURLPrefix + '/' + groupDetails._id,
+ data: groupDetails,
+ });
+ };
+
+ Group.join = function(gid) {
+ return $http({
+ method: "POST",
+ url: groupApiURLPrefix + '/' + gid + '/join',
+ });
+ };
+
+ Group.rejectInvite = function(gid) {
+ return $http({
+ method: "POST",
+ url: groupApiURLPrefix + '/' + gid + '/reject-invite',
+ });
+ };
+
+ Group.leave = function(gid, keep) {
+ return $http({
+ method: "POST",
+ url: groupApiURLPrefix + '/' + gid + '/leave',
+ data: {
+ keep: keep,
+ }
+ });
+ };
+
+ Group.removeMember = function(gid, memberId, message) {
+ return $http({
+ method: "POST",
+ url: groupApiURLPrefix + gid + '/removeMember/' + memberId,
+ data: {
+ message: message,
+ },
+ });
+ };
+
+ Group.invite = function(gid, invitationDetails) {
+ return $http({
+ method: "POST",
+ url: groupApiURLPrefix + '/' + gid + '/invite',
+ data: {
+ uuids: invitationDetails.uuids,
+ emails: invitationDetails.emails,
+ },
+ });
+ };
+
+ Group.startQuest = function(gid) {
+ return $http({
+ method: "POST",
+ url: groupApiURLPrefix + '/' + gid + '/questAccept',
+ });
+ };
+
+ function party () {
+ var deferred = $q.defer();
+
+ if (!data.party) {
+ Group.get('party')
+ .then(function (response) {
+ data.party = response.data.data;
+ deferred.resolve(data.party);
+ }, function (response) {
+ deferred.reject(response);
+ });
+ } else {
+ deferred.resolve(data.party);
+ }
+
+ return deferred.promise;
}
- function publicGuilds() {
+ function publicGuilds () {
+ var deferred = $q.defer();
+
+ if (!data.publicGuilds) {
+ Group.getGroups('publicGuilds')
+ .then(function (response) {
+ data.publicGuilds = response.data.data;
+ deferred.resolve(data.publicGuilds);
+ }, function (response) {
+ deferred.reject(response);
+ });
+ } else {
+ deferred.resolve(data.publicGuilds);
+ }
+
+ return deferred.promise;
//TODO combine these as {type:'guilds,public'} and create a $filter() to separate them
- if (!data.publicGuilds) data.publicGuilds = Group.query({type:'public'});
- return data.publicGuilds;
}
- function myGuilds() {
- if (!data.myGuilds) data.myGuilds = Group.query({type:'guilds'});
- return data.myGuilds;
+ function myGuilds () {
+ var deferred = $q.defer();
+
+ if (!data.myGuilds) {
+ Group.getGroups('privateGuilds')
+ .then(function (response) {
+ data.myGuilds = response.data.data;
+ deferred.resolve(data.myGuilds);
+ }, function (response) {
+ deferred.reject(response);
+ });
+ } else {
+ deferred.resolve(data.myGuilds);
+ }
+
+ return deferred.promise;
}
- function tavern() {
- if (!data.tavern) data.tavern = Group.get({gid:'habitrpg'});
- return data.tavern;
+ function tavern () {
+ var deferred = $q.defer();
+
+ if (!data.tavern) {
+ Group.get('habitrpg')
+ .then(function (response) {
+ data.tavern = response.data.data;
+ deferred.resolve(data.tavern);
+ }, function (response) {
+ deferred.reject(response);
+ });
+ } else {
+ deferred.resolve(data.tavern);
+ }
+
+ return deferred.promise;
}
- function inviteOrStartParty(group) {
+ function inviteOrStartParty (group) {
Analytics.track({'hitType':'event','eventCategory':'button','eventAction':'click','eventLabel':'Invite Friends'});
if (group.type === "party" || $location.$$path === "/options/groups/party") {
- group.type = 'party';
- $rootScope.openModal('invite-party', {
- controller:'InviteToGroupCtrl',
- resolve: {
- injectedGroup: function(){ return group; }
- }
- });
+ group.type = 'party';
+ $rootScope.openModal('invite-party', {
+ controller:'InviteToGroupCtrl',
+ resolve: {
+ injectedGroup: function(){ return group; }
+ }
+ });
} else {
- $location.path("/options/groups/party");
+ $location.path("/options/groups/party");
}
}
@@ -86,7 +197,6 @@
inviteOrStartParty: inviteOrStartParty,
data: data,
- Group: Group
- }
- }
-})();
+ Group: Group,
+ };
+ }]);
diff --git a/website/src/controllers/api-v3/groups.js b/website/src/controllers/api-v3/groups.js
index 3f4a7aabb4..91800ea660 100644
--- a/website/src/controllers/api-v3/groups.js
+++ b/website/src/controllers/api-v3/groups.js
@@ -278,7 +278,10 @@ api.joinGroup = {
await Q.all(promises);
let response = Group.toJSONCleanChat(promises[0], user);
- response.leader = (await User.findById(response.leader).select(nameFields).exec()).toJSON({minimize: true});
+ let leader = await User.findById(response.leader).select(nameFields).exec();
+ if (leader) {
+ response.leader = leader.toJSON({minimize: true});
+ }
res.respond(200, response);
firebase.addUserToGroup(group._id, user._id);
diff --git a/website/views/options/social/party/party-invitation.jade b/website/views/options/social/party/party-invitation.jade
index f4972e6e41..0bfd72b6d8 100644
--- a/website/views/options/social/party/party-invitation.jade
+++ b/website/views/options/social/party/party-invitation.jade
@@ -5,5 +5,4 @@
data-type='party',
ng-click='join(user.invitations.party)'
)=env.t('accept')
- a.btn.btn-danger(ng-click='reject()')=env.t('reject')
-
+ a.btn.btn-danger(ng-click='reject(user.invitations.party)')=env.t('reject')