Skip to content

Commit

Permalink
Merge branch 'release' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
SabreCat committed Oct 25, 2023
2 parents affeca6 + bc358c3 commit 1026a72
Show file tree
Hide file tree
Showing 16 changed files with 822 additions and 67 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "habitica",
"description": "A habit tracker app which treats your goals like a Role Playing Game.",
"version": "5.9.1",
"version": "5.10.0",
"main": "./website/server/index.js",
"dependencies": {
"@babel/core": "^7.22.10",
Expand Down
62 changes: 62 additions & 0 deletions test/api/v3/integration/challenges/POST-challenge_flag.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { v4 as generateUUID } from 'uuid';
import {
generateChallenge,
createAndPopulateGroup,
translate as t,
} from '../../../../helpers/api-integration/v3';

describe('POST /challenges/:challengeId/flag', () => {
let user;
let challenge;

beforeEach(async () => {
const { group, groupLeader } = await createAndPopulateGroup({
groupDetails: {
name: 'TestParty',
type: 'party',
privacy: 'private',
},
members: 1,
});

user = groupLeader;

challenge = await generateChallenge(user, group);
});

it('returns an error when challenge is not found', async () => {
await expect(user.post(`/challenges/${generateUUID()}/flag`))
.to.eventually.be.rejected.and.eql({
code: 404,
error: 'NotFound',
message: t('challengeNotFound'),
});
});

it('flags a challenge', async () => {
const flagResult = await user.post(`/challenges/${challenge._id}/flag`);

expect(flagResult.challenge.flags[user._id]).to.equal(true);
expect(flagResult.challenge.flagCount).to.equal(1);
});

it('flags a challenge with a higher count when from an admin', async () => {
await user.update({ 'contributor.admin': true });

const flagResult = await user.post(`/challenges/${challenge._id}/flag`);

expect(flagResult.challenge.flags[user._id]).to.equal(true);
expect(flagResult.challenge.flagCount).to.equal(5);
});

it('returns an error when user tries to flag a challenge that is already flagged', async () => {
await user.post(`/challenges/${challenge._id}/flag`);

await expect(user.post(`/challenges/${challenge._id}/flag`))
.to.eventually.be.rejected.and.eql({
code: 404,
error: 'NotFound',
message: t('messageChallengeFlagAlreadyReported'),
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { v4 as generateUUID } from 'uuid';
import {
generateChallenge,
createAndPopulateGroup,
translate as t,
} from '../../../../helpers/api-integration/v3';

describe('POST /challenges/:challengeId/clearflags', () => {
let admin;
let nonAdmin;
let challenge;

beforeEach(async () => {
const { group, groupLeader, members } = await createAndPopulateGroup({
groupDetails: {
name: 'TestParty',
type: 'party',
privacy: 'private',
},
members: 1,
});

admin = groupLeader;
[nonAdmin] = members;

await admin.update({ 'permissions.moderator': true });

challenge = await generateChallenge(admin, group);
await admin.post(`/challenges/${challenge._id}/flag`);
});

it('returns error when non-admin attempts to clear flags', async () => {
await expect(nonAdmin.post(`/challenges/${generateUUID()}/clearflags`))
.to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('messageGroupChatAdminClearFlagCount'),
});
});

it('returns an error when challenge is not found', async () => {
await expect(admin.post(`/challenges/${generateUUID()}/clearflags`))
.to.eventually.be.rejected.and.eql({
code: 404,
error: 'NotFound',
message: t('challengeNotFound'),
});
});

it('clears flags and sets mod flag to false', async () => {
await nonAdmin.post(`/challenges/${challenge._id}/flag`);
const flagResult = await admin.post(`/challenges/${challenge._id}/clearflags`);

expect(flagResult.challenge.flagCount).to.eql(0);
expect(flagResult.challenge.flags).to.have.property(admin._id, false);
expect(flagResult.challenge.flags).to.have.property(nonAdmin._id, true);
});
});
91 changes: 83 additions & 8 deletions website/client/src/components/challenges/challengeDetail.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<template>
<div class="row">
<report-challenge-modal />
<challenge-modal @updatedChallenge="updatedChallenge" />
<leave-challenge-modal
:challenge-id="challenge._id"
Expand All @@ -9,11 +10,27 @@
:members="members"
:challenge-id="challenge._id"
:prize="challenge.prize"
:flag-count="challenge.flagCount"
/>
<challenge-member-progress-modal :challenge-id="challenge._id" />
<div class="col-12 col-md-8 standard-page">
<div class="row">
<div class="col-12 col-md-6">
<div
v-if="canViewFlags"
class="flagged"
>
<div
v-if="flaggedNotHidden"
>
{{ $t("flaggedNotHidden") }}
</div>
<div
v-else-if="flaggedAndHidden"
>
{{ $t("flaggedAndHidden") }}
</div>
</div>
<h1 v-markdown="challenge.name"></h1>
<div>
<span class="mr-1 ml-0 d-block">
Expand Down Expand Up @@ -41,7 +58,7 @@
createdBy string (helps with RTL languages)-->
<!-- @TODO: Implement in V2 strong.margin-left
(v-once).svg-icon.calendar-icon(v-html="icons.calendarIcon")
| {{$t('endDate')}}
{{$t('endDate')}}
// "endDate": "End Date: <% endDate %>",-->
<!-- span {{challenge.endDate}}-->
</div>
Expand Down Expand Up @@ -169,13 +186,16 @@
v-if="isLeader || isAdmin"
class="button-container"
>
<button
v-once
class="btn btn-primary"
@click="cloneChallenge()"
>
{{ $t('clone') }}
</button>
<div>
<button
class="btn"
:disabled="flaggedAndHidden"
:class="flaggedAndHidden ? 'disabled btn-disabled' : 'btn-primary'"
@click="cloneChallenge()"
>
{{ $t('clone') }}
</button>
</div>
</div>
<div
v-if="isLeader || isAdmin"
Expand All @@ -201,6 +221,17 @@
{{ $t('endChallenge') }}
</button>
</div>
<div
class="button-container"
>
<button
v-once
class="btn btn-danger"
@click="reportChallenge()"
>
{{ $t('report') }}
</button>
</div>
<div>
<sidebar-section :title="$t('challengeSummary')">
<p v-markdown="challenge.summary"></p>
Expand Down Expand Up @@ -249,6 +280,17 @@
}
}
.btn-disabled {
background-color: $gray-700;
color: $gray-50;
box-shadow: none;
cursor: arrow;
&:hover {
box-shadow: none;
}
}
.calendar-icon {
width: 12px;
display: inline-block;
Expand Down Expand Up @@ -312,6 +354,15 @@
margin-right: .5em;
}
}
.flagged {
margin-left: 0em;
color: $red-10;
span {
margin-left: 0em;
}
}
</style>

<script>
Expand All @@ -332,6 +383,7 @@ import challengeModal from './challengeModal';
import challengeMemberProgressModal from './challengeMemberProgressModal';
import challengeMemberSearchMixin from '@/mixins/challengeMemberSearch';
import leaveChallengeModal from './leaveChallengeModal';
import reportChallengeModal from './reportChallengeModal';
import sidebarSection from '../sidebarSection';
import userLink from '../userLink';
import groupLink from '../groupLink';
Expand All @@ -350,6 +402,7 @@ export default {
components: {
closeChallengeModal,
leaveChallengeModal,
reportChallengeModal,
challengeModal,
challengeMemberProgressModal,
memberSearchDropdown,
Expand Down Expand Up @@ -401,6 +454,20 @@ export default {
canJoin () {
return !this.isMember;
},
// canViewFlags should allow only moderators/admins to see flags
canViewFlags () {
const isModerator = this.hasPermission(this.user, 'moderator');
if (isModerator && this.challenge.flagCount > 0) return true;
return false;
},
// flaggedNotHidden should allow mods/admins & challenge owner to see flags
flaggedNotHidden () {
return this.challenge.flagCount === 1;
},
// flaggedAndHidden should only allow admin to see challenge & flags
flaggedAndHidden () {
return this.challenge.flagCount > 1;
},
},
watch: {
'challenge.name': {
Expand Down Expand Up @@ -589,6 +656,14 @@ export default {
challenge: this.challenge,
});
},
reportChallenge () {
this.$root.$emit('habitica::report-challenge', {
challenge: this.challenge,
});
},
async showCannotCloneModal () {
this.$root.$emit('bv::show::modal', 'cannot-clone-modal');
},
},
};
</script>
1 change: 0 additions & 1 deletion website/client/src/components/challenges/challengeItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,6 @@
}
}
}
}
</style>

Expand Down
Loading

0 comments on commit 1026a72

Please sign in to comment.