diff --git a/test/api/v3/integration/groups/GET-groups.test.js b/test/api/v3/integration/groups/GET-groups.test.js
index 756a315006..b7c8fbd942 100644
--- a/test/api/v3/integration/groups/GET-groups.test.js
+++ b/test/api/v3/integration/groups/GET-groups.test.js
@@ -16,6 +16,12 @@ describe('GET /groups', () => {
const NUMBER_OF_USERS_PRIVATE_GUILDS = 1;
const NUMBER_OF_GROUPS_USER_CAN_VIEW = 5;
const GUILD_PER_PAGE = 30;
+ let categories = [{
+ slug: 'newCat',
+ name: 'New Category',
+ }];
+ let publicGuildNotMember;
+ let privateGuildUserIsMemberOf;
before(async () => {
await resetHabiticaDB();
@@ -31,16 +37,18 @@ describe('GET /groups', () => {
await leader.post(`/groups/${publicGuildUserIsMemberOf._id}/invite`, { uuids: [user._id]});
await user.post(`/groups/${publicGuildUserIsMemberOf._id}/join`);
- await generateGroup(leader, {
+ publicGuildNotMember = await generateGroup(leader, {
name: 'public guild - is not member',
type: 'guild',
privacy: 'public',
+ categories,
});
- let privateGuildUserIsMemberOf = await generateGroup(leader, {
+ privateGuildUserIsMemberOf = await generateGroup(leader, {
name: 'private guild - is member',
type: 'guild',
privacy: 'private',
+ categories,
});
await leader.post(`/groups/${privateGuildUserIsMemberOf._id}/invite`, { uuids: [user._id]});
await user.post(`/groups/${privateGuildUserIsMemberOf._id}/join`);
@@ -100,6 +108,50 @@ describe('GET /groups', () => {
.to.eventually.have.a.lengthOf(NUMBER_OF_PUBLIC_GUILDS);
});
+ describe('filters', () => {
+ it('returns public guilds filtered by category', async () => {
+ let guilds = await user.get(`/groups?type=publicGuilds&categories=${categories[0].slug}`);
+
+ expect(guilds[0]._id).to.equal(publicGuildNotMember._id);
+ });
+
+ it('returns private guilds filtered by category', async () => {
+ let guilds = await user.get(`/groups?type=privateGuilds&categories=${categories[0].slug}`);
+
+ expect(guilds[0]._id).to.equal(privateGuildUserIsMemberOf._id);
+ });
+
+ it('filters public guilds by size', async () => {
+ await generateGroup(user, {
+ name: 'guild1',
+ type: 'guild',
+ privacy: 'public',
+ memberCount: 1,
+ });
+
+ // @TODO: anyway to set higher memberCount in tests right now?
+
+ let guilds = await user.get('/groups?type=publicGuilds&minMemberCount=3');
+
+ expect(guilds.length).to.equal(0);
+ });
+
+ it('filters private guilds by size', async () => {
+ await generateGroup(user, {
+ name: 'guild1',
+ type: 'guild',
+ privacy: 'private',
+ memberCount: 1,
+ });
+
+ // @TODO: anyway to set higher memberCount in tests right now?
+
+ let guilds = await user.get('/groups?type=privateGuilds&minMemberCount=3');
+
+ expect(guilds.length).to.equal(0);
+ });
+ });
+
describe('public guilds pagination', () => {
it('req.query.paginate must be a boolean string', async () => {
await expect(user.get('/groups?paginate=aString&type=publicGuilds'))
@@ -149,8 +201,8 @@ describe('GET /groups', () => {
await expect(user.get('/groups?type=publicGuilds&paginate=true&page=1'))
.to.eventually.have.a.lengthOf(GUILD_PER_PAGE);
let page2 = await expect(user.get('/groups?type=publicGuilds&paginate=true&page=2'))
- .to.eventually.have.a.lengthOf(1 + 2); // 1 created now, 2 by other tests
- expect(page2[2].name).to.equal('guild with less members');
+ .to.eventually.have.a.lengthOf(1 + 3); // 1 created now, 3 by other tests
+ expect(page2[3].name).to.equal('guild with less members');
});
});
diff --git a/test/api/v3/integration/groups/GET-groups_groupId_members.test.js b/test/api/v3/integration/groups/GET-groups_groupId_members.test.js
index 72b12453d9..e74c6acfa6 100644
--- a/test/api/v3/integration/groups/GET-groups_groupId_members.test.js
+++ b/test/api/v3/integration/groups/GET-groups_groupId_members.test.js
@@ -66,11 +66,25 @@ describe('GET /groups/:groupId/members', () => {
expect(res[0].profile).to.have.all.keys(['name']);
});
- it('req.query.includeAllPublicFields === true only works with parties', async () => {
+ it('req.query.includeAllPublicFields === true works with guilds', async () => {
let group = await generateGroup(user, {type: 'guild', name: generateUUID()});
- let res = await user.get(`/groups/${group._id}/members?includeAllPublicFields=true`);
- expect(res[0]).to.have.all.keys(['_id', 'id', 'profile']);
- expect(res[0].profile).to.have.all.keys(['name']);
+ let [memberRes] = await user.get(`/groups/${group._id}/members?includeAllPublicFields=true`);
+
+ expect(memberRes).to.have.all.keys([ // works as: object has all and only these keys
+ '_id', 'id', 'preferences', 'profile', 'stats', 'achievements', 'party',
+ 'backer', 'contributor', 'auth', 'items', 'inbox',
+ ]);
+ expect(Object.keys(memberRes.auth)).to.eql(['timestamps']);
+ expect(Object.keys(memberRes.preferences).sort()).to.eql([
+ 'size', 'hair', 'skin', 'shirt',
+ 'chair', 'costume', 'sleep', 'background', 'tasks',
+ ].sort());
+
+ expect(memberRes.stats.maxMP).to.exist;
+ expect(memberRes.stats.maxHealth).to.equal(common.maxHealth);
+ expect(memberRes.stats.toNextLevel).to.equal(common.tnl(memberRes.stats.lvl));
+ expect(memberRes.inbox.optOut).to.exist;
+ expect(memberRes.inbox.messages).to.not.exist;
});
it('populates all public fields if req.query.includeAllPublicFields === true and it is a party', async () => {
diff --git a/test/api/v3/integration/groups/PUT-groups.test.js b/test/api/v3/integration/groups/PUT-groups.test.js
index 84b49d91bd..0cf30b5d03 100644
--- a/test/api/v3/integration/groups/PUT-groups.test.js
+++ b/test/api/v3/integration/groups/PUT-groups.test.js
@@ -45,6 +45,20 @@ describe('PUT /group', () => {
expect(updatedGroup.name).to.equal(groupUpdatedName);
});
+ it('updates a group categories', async () => {
+ let categories = [{
+ slug: 'newCat',
+ name: 'New Category',
+ }];
+
+ let updatedGroup = await leader.put(`/groups/${groupToUpdate._id}`, {
+ categories,
+ });
+
+ expect(updatedGroup.categories[0].slug).to.eql(categories[0].slug);
+ expect(updatedGroup.categories[0].name).to.eql(categories[0].name);
+ });
+
it('allows an admin to update a guild', async () => {
let updatedGroup = await adminUser.put(`/groups/${groupToUpdate._id}`, {
name: groupUpdatedName,
diff --git a/website/client/components/challenges/groupChallenges.vue b/website/client/components/challenges/groupChallenges.vue
new file mode 100644
index 0000000000..81169d9818
--- /dev/null
+++ b/website/client/components/challenges/groupChallenges.vue
@@ -0,0 +1,100 @@
+
+div
+ .row.no-quest-section(v-if='challenges.length === 0')
+ .col-12.text-center
+ .svg-icon.challenge-icon(v-html="icons.challengeIcon")
+ h4(v-once) {{ $t('haveNoChallenges') }}
+ p(v-once) {{ $t('challengeDescription') }}
+ button.btn.btn-secondary(v-once) {{ $t('createChallenge') }}
+ .col-12.challenge-item(v-for='challenge in challenges')
+ .row
+ .col-9
+ router-link.title(:to="{ name: 'challenge', params: { challengeId: challenge._id } }")
+ strong {{challenge.name}}
+ p {{challenge.description}}
+ div
+ .svg-icon.member-icon(v-html="icons.memberIcon")
+ .member-count {{challenge.memberCount}}
+ .col-3
+ div
+ span.svg-icon.gem(v-html="icons.gemIcon")
+ span.prize {{challenge.prize}}
+ div.prize-title Prize
+
+
+
+
+
diff --git a/website/client/components/groups/guild.vue b/website/client/components/groups/guild.vue
index 54038efbf4..3b08093194 100644
--- a/website/client/components/groups/guild.vue
+++ b/website/client/components/groups/guild.vue
@@ -137,12 +137,7 @@
.toggle-down(@click="sections.challenges = !sections.challenges", v-if="!sections.challenges")
.svg-icon(v-html="icons.downIcon")
.section(v-if="sections.challenges")
- .row.no-quest-section(v-if='!hasChallenges')
- .col-12.text-center
- .svg-icon(v-html="icons.challengeIcon")
- h4(v-once) {{ $t('haveNoChallenges') }}
- p(v-once) {{ $t('challengeDescription') }}
- button.btn.btn-secondary(v-once) {{ $t('createChallenge') }}
+ group-challenges(:groupId='groupId')
div.text-center
button.btn.btn-primary(class='btn-danger', v-if='isMember') {{ $t('leave') }}
@@ -359,6 +354,7 @@ import groupFormModal from './groupFormModal';
import inviteModal from './inviteModal';
import memberModal from '../members/memberModal';
import chatMessage from '../chat/chatMessages';
+import groupChallenges from '../challenges/groupChallenges';
import bCollapse from 'bootstrap-vue/lib/components/collapse';
import bCard from 'bootstrap-vue/lib/components/card';
@@ -372,7 +368,6 @@ import likedIcon from 'assets/svg/liked.svg';
import reportIcon from 'assets/svg/report.svg';
import gemIcon from 'assets/svg/gem.svg';
import questIcon from 'assets/svg/quest.svg';
-import challengeIcon from 'assets/svg/challenge.svg';
import informationIcon from 'assets/svg/information.svg';
import questBackground from 'assets/svg/quest-background-border.svg';
import upIcon from 'assets/svg/up.svg';
@@ -391,6 +386,7 @@ export default {
groupFormModal,
chatMessage,
inviteModal,
+ groupChallenges,
},
directives: {
bToggle,
@@ -406,7 +402,6 @@ export default {
gem: gemIcon,
liked: likedIcon,
questIcon,
- challengeIcon,
information: informationIcon,
questBackground,
upIcon,
diff --git a/website/client/components/groups/publicGuildItem.vue b/website/client/components/groups/publicGuildItem.vue
index 40cf650d99..ecae214d16 100644
--- a/website/client/components/groups/publicGuildItem.vue
+++ b/website/client/components/groups/publicGuildItem.vue
@@ -8,7 +8,7 @@
.col-md-10
.row
.col-md-8
- router-link(:to="{ name: 'guild', params: { guildId: guild._id } }")
+ router-link(:to="{ name: 'guild', params: { groupId: guild._id } }")
h3 {{ guild.name }}
p {{ guild.description }}
.col-md-2.cta-container
@@ -22,69 +22,70 @@
.col-md-12
.category-label(v-for="category in guild.categories")
| {{category}}
- span.recommend-text Suggested because you’re new to Habitica.
+ span.recommend-text(v-if='showSuggested(guild._id)') Suggested because you’re new to Habitica.