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 @@ + + + + + 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.