mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-16 14:17:22 +01:00
Group plans misc fixes (#8388)
* Added notification for approval request in the group leaders language * Added test for group task meta actions. Added sync when user claims * Added tests for group task actions. Ensured assigned members are synce when added or removed * Fixed approval required toggle * Added support for users with comma in their name * Fixed sync issue when user is approved and reloads the website * Added advance options for group rewards * Added back ticks to group claim message * Fixed disappearing tasks that need approval * Up chat limit to 400 for subbed groups * Fixed line endings * Updated activie subscription check * Added group isSubscribed function * Changed to isAfter
This commit is contained in:
@@ -34,6 +34,10 @@ describe('POST /tasks/:id/score/:direction', () => {
|
||||
});
|
||||
|
||||
it('prevents user from scoring a task that needs to be approved', async () => {
|
||||
await user.update({
|
||||
'preferences.language': 'cs',
|
||||
});
|
||||
|
||||
let memberTasks = await member.get('/tasks/user');
|
||||
let syncedTask = find(memberTasks, findAssignedTask);
|
||||
|
||||
@@ -52,7 +56,7 @@ describe('POST /tasks/:id/score/:direction', () => {
|
||||
expect(user.notifications[0].data.message).to.equal(t('userHasRequestedTaskApproval', {
|
||||
user: member.auth.local.username,
|
||||
taskName: updatedTask.text,
|
||||
}));
|
||||
}, 'cs')); // This test only works if we have the notification translated
|
||||
expect(user.notifications[0].data.groupId).to.equal(guild._id);
|
||||
|
||||
expect(updatedTask.group.approval.requested).to.equal(true);
|
||||
|
||||
@@ -809,6 +809,20 @@ describe('Group Model', () => {
|
||||
expect(party.chat).to.have.a.lengthOf(200);
|
||||
});
|
||||
|
||||
it('cuts down chat to 400 messages when group is subcribed', () => {
|
||||
party.purchased.plan.customerId = 'test-customer-id';
|
||||
|
||||
for (let i = 0; i < 420; i++) {
|
||||
party.chat.push({ text: 'a message' });
|
||||
}
|
||||
|
||||
expect(party.chat).to.have.a.lengthOf(420);
|
||||
|
||||
party.sendChat('message');
|
||||
|
||||
expect(party.chat).to.have.a.lengthOf(400);
|
||||
});
|
||||
|
||||
it('updates users about new messages in party', () => {
|
||||
party.sendChat('message');
|
||||
|
||||
|
||||
63
test/client-old/spec/controllers/groupTaskActionsCtrlSpec.js
Normal file
63
test/client-old/spec/controllers/groupTaskActionsCtrlSpec.js
Normal file
@@ -0,0 +1,63 @@
|
||||
describe('Group Tasks Meta Actions Controller', () => {
|
||||
let rootScope, scope, user, userSerivce;
|
||||
|
||||
beforeEach(() => {
|
||||
module(function($provide) {
|
||||
$provide.value('User', {});
|
||||
});
|
||||
|
||||
inject(($rootScope, $controller) => {
|
||||
rootScope = $rootScope;
|
||||
|
||||
user = specHelper.newUser();
|
||||
user._id = "unique-user-id";
|
||||
userSerivce = {user: user};
|
||||
|
||||
scope = $rootScope.$new();
|
||||
|
||||
scope.task = {
|
||||
group: {
|
||||
assignedUsers: [],
|
||||
approval: {
|
||||
required: false,
|
||||
}
|
||||
},
|
||||
};
|
||||
scope.task._edit = angular.copy(scope.task);
|
||||
|
||||
$controller('GroupTaskActionsCtrl', {$scope: scope, User: userSerivce});
|
||||
});
|
||||
});
|
||||
|
||||
describe('toggleTaskRequiresApproval', function () {
|
||||
it('toggles task approval required field from false to true', function () {
|
||||
scope.toggleTaskRequiresApproval();
|
||||
expect(scope.task._edit.group.approval.required).to.be.true;
|
||||
});
|
||||
|
||||
it('toggles task approval required field from true to false', function () {
|
||||
scope.task._edit.group.approval.required = true;
|
||||
scope.toggleTaskRequiresApproval();
|
||||
expect(scope.task._edit.group.approval.required).to.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('assign events', function () {
|
||||
it('adds a group member to assigned users on "addedGroupMember" event ', () => {
|
||||
var testId = 'test-id';
|
||||
rootScope.$broadcast('addedGroupMember', testId);
|
||||
expect(scope.task.group.assignedUsers).to.contain(testId);
|
||||
expect(scope.task._edit.group.assignedUsers).to.contain(testId);
|
||||
});
|
||||
|
||||
it('removes a group member to assigned users on "addedGroupMember" event ', () => {
|
||||
var testId = 'test-id';
|
||||
scope.task.group.assignedUsers.push(testId);
|
||||
scope.task._edit.group.assignedUsers.push(testId);
|
||||
rootScope.$broadcast('removedGroupMember', testId);
|
||||
expect(scope.task.group.assignedUsers).to.not.contain(testId);
|
||||
expect(scope.task._edit.group.assignedUsers).to.not.contain(testId);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,42 @@
|
||||
describe('Group Task Actions Controller', () => {
|
||||
let scope, user, userSerivce;
|
||||
|
||||
beforeEach(() => {
|
||||
module(function($provide) {
|
||||
$provide.value('User', {});
|
||||
});
|
||||
|
||||
inject(($rootScope, $controller) => {
|
||||
user = specHelper.newUser();
|
||||
user._id = "unique-user-id";
|
||||
userSerivce = {user: user};
|
||||
userSerivce.sync = sandbox.stub();
|
||||
|
||||
scope = $rootScope.$new();
|
||||
|
||||
$controller('GroupTaskMetaActionsCtrl', {$scope: scope, User: userSerivce});
|
||||
|
||||
scope.task = {
|
||||
group: {
|
||||
assignedUsers: [],
|
||||
},
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
describe('claim', () => {
|
||||
beforeEach(() => {
|
||||
sandbox.stub(window, 'confirm').returns(true);
|
||||
});
|
||||
|
||||
it('adds user to assigned users of scope task ', () => {
|
||||
scope.claim();
|
||||
expect(scope.task.group.assignedUsers).to.contain(user._id);
|
||||
});
|
||||
|
||||
it('syncs user tasks ', () => {
|
||||
scope.claim();
|
||||
expect(userSerivce.sync).to.be.calledOnce;
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -44,6 +44,7 @@ module.exports = function karmaConfig (config) {
|
||||
'../../../website/client-old/js/filters/**/*.js',
|
||||
'../../../website/client-old/js/directives/**/*.js',
|
||||
'../../../website/client-old/js/controllers/**/*.js',
|
||||
'../../../website/client-old/js/components/**/*.js',
|
||||
|
||||
'../../../test/client-old/spec/specHelper.js',
|
||||
'../../../test/client-old/spec/**/*.js',
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
allowedTags: allowedTags,
|
||||
allowDuplicates: false,
|
||||
preserveCase: true,
|
||||
delimeter: '|',
|
||||
placeholder: window.env.t('assignFieldPlaceholder'),
|
||||
onBeforeTagAdd: function(event, tag) {
|
||||
return confirm(window.env.t('confirmAddTag', {tag: tag}));
|
||||
|
||||
@@ -3,16 +3,30 @@ habitrpg.controller('GroupTaskActionsCtrl', ['$scope', 'Shared', 'Tasks', 'User'
|
||||
$scope.assignedMembers = [];
|
||||
$scope.user = User.user;
|
||||
|
||||
// We must use a separate field here, because task.group is private. So, instead, we send this tmp field to alter the approval.
|
||||
$scope.task._edit.requiresApproval = false;
|
||||
if ($scope.task.group.approval.required) {
|
||||
$scope.task._edit.requiresApproval = $scope.task.group.approval.required;
|
||||
}
|
||||
|
||||
$scope.toggleTaskRequiresApproval = function () {
|
||||
$scope.task._edit.group.approval.required = !$scope.task._edit.group.approval.required;
|
||||
$scope.task._edit.requiresApproval = $scope.task._edit.group.approval.required;
|
||||
}
|
||||
|
||||
$scope.$on('addedGroupMember', function(evt, userId) {
|
||||
$scope.task.group.assignedUsers.push(userId);
|
||||
if ($scope.task._edit) $scope.task._edit.group.assignedUsers.push(userId);
|
||||
Tasks.assignTask($scope.task.id, userId);
|
||||
});
|
||||
|
||||
$scope.$on('removedGroupMember', function(evt, userId) {
|
||||
var index = $scope.task.group.assignedUsers.indexOf(userId);
|
||||
$scope.task.group.assignedUsers.splice(index, 1);
|
||||
if ($scope.task._edit) {
|
||||
var index = $scope.task._edit.group.assignedUsers.indexOf(userId);
|
||||
$scope.task._edit.group.assignedUsers.splice(index, 1);
|
||||
}
|
||||
Tasks.unAssignTask($scope.task.id, userId);
|
||||
});
|
||||
}]);
|
||||
|
||||
@@ -7,6 +7,7 @@ habitrpg.controller('GroupTaskMetaActionsCtrl', ['$scope', 'Shared', 'Tasks', 'U
|
||||
if (!confirm("Are you sure you want to claim this task?")) return;
|
||||
Tasks.assignTask($scope.task.id, $scope.user._id);
|
||||
$scope.task.group.assignedUsers.push($scope.user._id);
|
||||
User.sync();
|
||||
};
|
||||
|
||||
$scope.userIsAssigned = function () {
|
||||
|
||||
@@ -177,7 +177,7 @@ habitrpg.controller('GroupTasksCtrl', ['$scope', 'Shared', 'Tasks', 'User', func
|
||||
|
||||
var claimingUsers = [];
|
||||
task.group.assignedUsers.forEach(function (userId) {
|
||||
claimingUsers.push(memberIdToProfileNameMap[userId]);
|
||||
claimingUsers.push('"' + memberIdToProfileNameMap[userId] + '"');
|
||||
})
|
||||
|
||||
if (claimingUsers.length > 0) content += window.env.t('claimedBy', {claimingUsers: claimingUsers.join(', ')});
|
||||
|
||||
@@ -171,6 +171,7 @@ habitrpg.controller('NotificationCtrl',
|
||||
if (scoreTaskNotification) {
|
||||
Notification.markdown(scoreTaskNotification.data.message);
|
||||
User.score({params:{task: scoreTaskNotification.data.scoreTask, direction: "up"}});
|
||||
User.sync();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -109,6 +109,8 @@ habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User','N
|
||||
} else {
|
||||
$scope.score(task, "down");
|
||||
}
|
||||
|
||||
if (task.group && task.group.approval && task.group.approval.required && !task.group.approval.approved) task.completed = false;
|
||||
};
|
||||
|
||||
$scope.saveTask = function(task, stayOpen, isSaveAndClose) {
|
||||
|
||||
@@ -247,7 +247,7 @@
|
||||
"approvalsTitle": "Tasks Awaiting Approval",
|
||||
"upgradeTitle": "Upgrade",
|
||||
"blankApprovalsDescription": "When your group completes tasks that need your approval, they'll appear here! Adjust approval requirement settings under task editing.",
|
||||
"userIsClamingTask": "<%= username %> has claimed \"<%= task %>\"",
|
||||
"userIsClamingTask": "`<%= username %> has claimed \"<%= task %>\"`",
|
||||
"approvalRequested": "Approval Requested",
|
||||
"refreshApprovals": "Refresh Approvals",
|
||||
"refreshGroupTasks": "Refresh Group Tasks",
|
||||
|
||||
@@ -354,7 +354,7 @@ api.scoreTask = {
|
||||
message: res.t('userHasRequestedTaskApproval', {
|
||||
user: user.profile.name,
|
||||
taskName: task.text,
|
||||
}),
|
||||
}, groupLeader.preferences.language),
|
||||
groupId: group._id,
|
||||
});
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import moment from 'moment';
|
||||
import mongoose from 'mongoose';
|
||||
import {
|
||||
model as User,
|
||||
@@ -392,7 +393,17 @@ schema.methods.sendChat = function sendChat (message, user) {
|
||||
let newMessage = chatDefaults(message, user);
|
||||
|
||||
this.chat.unshift(newMessage);
|
||||
this.chat.splice(200);
|
||||
|
||||
const MAX_CHAT_COUNT = 200;
|
||||
const MAX_SUBBED_GROUP_CHAT_COUNT = 400;
|
||||
|
||||
let maxCount = MAX_CHAT_COUNT;
|
||||
|
||||
if (this.isSubscribed()) {
|
||||
maxCount = MAX_SUBBED_GROUP_CHAT_COUNT;
|
||||
}
|
||||
|
||||
this.chat.splice(maxCount);
|
||||
|
||||
// do not send notifications for guilds with more than 5000 users and for the tavern
|
||||
if (NO_CHAT_NOTIFICATIONS.indexOf(this._id) !== -1 || this.memberCount > LARGE_GROUP_COUNT_MESSAGE_CUTOFF) {
|
||||
@@ -882,8 +893,7 @@ schema.methods.leave = async function leaveGroup (user, keep = 'keep-all') {
|
||||
let group = this;
|
||||
let update = {};
|
||||
|
||||
let plan = group.purchased.plan;
|
||||
if (group.memberCount <= 1 && group.privacy === 'private' && plan && plan.customerId && !plan.dateTerminated) {
|
||||
if (group.memberCount <= 1 && group.privacy === 'private' && group.isSubscribed()) {
|
||||
throw new NotAuthorized(shared.i18n.t('cannotDeleteActiveGroup'));
|
||||
}
|
||||
|
||||
@@ -1136,6 +1146,12 @@ schema.methods.removeTask = async function groupRemoveTask (task) {
|
||||
}, {multi: true}).exec();
|
||||
};
|
||||
|
||||
schema.methods.isSubscribed = function isSubscribed () {
|
||||
let now = new Date();
|
||||
let plan = this.purchased.plan;
|
||||
return plan && plan.customerId && (!plan.dateTerminated || moment(plan.dateTerminated).isAfter(now));
|
||||
};
|
||||
|
||||
export let model = mongoose.model('Group', schema);
|
||||
|
||||
// initialize tavern if !exists (fresh installs)
|
||||
|
||||
@@ -5,6 +5,6 @@ script(type='text/ng-template', id='partials/groups.tasks.actions.html')
|
||||
|
||||
ul.priority-multiplier
|
||||
li {{requiresApproval}}
|
||||
button(type='button', ng-class='{active: task._edit.requiresApproval==true}',
|
||||
ng-click='task._edit.requiresApproval = !task._edit.requiresApproval')
|
||||
button(type='button', ng-class='{active: task._edit.group.approval.required == true}',
|
||||
ng-click='toggleTaskRequiresApproval()')
|
||||
=env.t('approvalRequired')
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
div(ng-if='::task.type!="reward"')
|
||||
div(ng-if='(task.type !== "reward") || (!obj.auth && obj.purchased && obj.purchased.active)')
|
||||
button.advanced-options-toggle.option-title.mega(type='button',
|
||||
ng-class='{active: task._edit._advanced}',
|
||||
ng-click='task._edit._advanced = !task._edit._advanced', tooltip=env.t('expandCollapse'))
|
||||
|
||||
Reference in New Issue
Block a user