Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(frontend): various improvements around invitations #2993

Merged
merged 5 commits into from
Oct 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion api/fixtures/campCollaborations.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ App\Entity\CampCollaboration:
camp: '@camp2'
inviteKey: "myInviteKeyCamp2"
inviteKeyHash: "ufVn1nkIodzMXLPB/ZI4JwNwSRg="
inviteEmail: '@profile6invited->email'
status: invited
role: member
campCollaboration1campPrototype:
Expand Down
37 changes: 12 additions & 25 deletions api/src/DataPersister/CampCollaborationDataPersister.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,7 @@ public function beforeCreate($data): CampCollaboration {
* @param CampCollaboration $data
*/
public function afterCreate($data): void {
/** @var CampCollaboration $data */
/** @var User $user */
$user = $this->security->getUser();
$emailToInvite = $data->user?->getEmail() ?? $data->inviteEmail;
if (CampCollaboration::STATUS_INVITED == $data->status && $emailToInvite) {
$this->mailService->sendInviteToCampMail($user, $data->camp, $data->inviteKey, $emailToInvite);
}
$this->sendInviteEmail($data);

$materialList = new MaterialList();
$materialList->campCollaboration = $data;
Expand All @@ -98,21 +92,7 @@ public function onBeforeStatusChange(CampCollaboration $data): CampCollaboration
}

public function onAfterStatusChange(CampCollaboration $data): void {
/** @var User $user */
$user = $this->security->getUser();
if (CampCollaboration::STATUS_INVITED == $data->status && ($data->inviteEmail || $data->user)) {
$campCollaborationUser = $data->user;
$inviteEmail = $data->inviteEmail;
if (null != $campCollaborationUser) {
$inviteEmail = $campCollaborationUser->getEmail();
}
$this->mailService->sendInviteToCampMail(
$user,
$data->camp,
$data->inviteKey,
$inviteEmail
);
}
$this->sendInviteEmail($data);
}

public function onBeforeResendInvitation(CampCollaboration $data) {
Expand All @@ -125,8 +105,15 @@ public function onBeforeResendInvitation(CampCollaboration $data) {
}

public function onAfterResendInvitation(CampCollaboration $data) {
/** @var User $user */
$user = $this->security->getUser();
$this->mailService->sendInviteToCampMail($user, $data->camp, $data->inviteKey, $data->inviteEmail);
$this->sendInviteEmail($data);
}

private function sendInviteEmail(CampCollaboration $data) {
if (CampCollaboration::STATUS_INVITED == $data->status && $data->getEmail()) {
/** @var User $user */
$user = $this->security->getUser();

$this->mailService->sendInviteToCampMail($user, $data->camp, $data->inviteKey, $data->getEmail());
}
}
}
7 changes: 7 additions & 0 deletions api/src/Entity/CampCollaboration.php
Original file line number Diff line number Diff line change
Expand Up @@ -297,4 +297,11 @@ public function removeDayResponsible(DayResponsible $dayResponsible): self {

return $this;
}

/**
* Returns user's email, fallback to inviteEmail if user not yet known (pending email invitation).
*/
public function getEmail(): string|null {
return $this->user?->getEmail() ?? $this->inviteEmail;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,34 @@ public function testResendInvitationSuccessfulWhenUserIsMember() {
self::assertEmailCount(1);
}

/**
* @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
*/
public function testResendInvitationSuccessfulWhenInvitedUserExists() {
/** @var CampCollaboration $campCollaboration */
$campCollaboration = static::$fixtures['campCollaboration6invitedWithUser'];
static::createClientWithCredentials(['email' => static::$fixtures['user1manager']->getEmail()])->request(
'PATCH',
'/camp_collaborations/'.$campCollaboration->getId().'/'.self::RESEND_INVITATION,
[
'json' => [],
'headers' => ['Content-Type' => 'application/merge-patch+json'],
]
);

$this->assertResponseStatusCodeSame(200);
$this->assertJsonContains([
'inviteEmail' => $campCollaboration->inviteEmail,
'status' => $campCollaboration->status,
'role' => $campCollaboration->role,
]);
self::assertEmailCount(1);
}

/**
* @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,6 @@ public function testAfterCreateSendsEmailIfUserSet() {
}

public function testAfterCreateDoesNotSendEmailIfNoInviteEmailSet() {
$this->security->expects(self::once())->method('getUser')->willReturn($this->user);

$this->mailService->expects(self::never())->method('sendInviteToCampMail');

$result = $this->dataPersister->beforeCreate($this->campCollaboration);
Expand All @@ -135,7 +133,6 @@ public function testAfterCreateDoesNotSendEmailIfNoInviteEmailSet() {
public function testAfterCreateDoesNotSendEmailIfStatusNotInvited($status) {
$this->campCollaboration->inviteEmail = 'e@mail.com';
$this->campCollaboration->status = $status;
$this->security->expects(self::once())->method('getUser')->willReturn($this->user);

$this->mailService->expects(self::never())->method('sendInviteToCampMail');

Expand Down
13 changes: 7 additions & 6 deletions frontend/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export default {
components: { LanguageSwitcher },
computed: {
profile() {
return this.$auth.user()
return this.$store.state.auth.user
},
deploymentTime() {
const timestamp = window.environment.DEPLOYMENT_TIME
Expand All @@ -57,11 +57,12 @@ export default {
},
async mounted() {
if (this.$auth.isLoggedIn()) {
this.profile._meta.load.then((profile) => {
if (VueI18n.availableLocales.includes(profile.language)) {
this.$store.commit('setLanguage', profile.language)
}
})
const user = await this.$auth.loadUser()
const profile = await user.profile()._meta.load

if (VueI18n.availableLocales.includes(profile.language)) {
this.$store.commit('setLanguage', profile.language)
}
}
},
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ export default {
if (!(typeof this.collaborator.user === 'function')) {
return false
}
return this.$auth.user().id === this.collaborator.user().id
return this.$store.state.auth.user.id === this.collaborator.user().id
},
},
methods: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
<slot>
{{
$tc('components.camp.collaboratorListItemDeactivate.warningText', 1, {
name: entity.user().displayName,
name: displayName,
})
}}
</slot>
Expand All @@ -33,6 +33,7 @@
<script>
import DialogForm from '@/components/dialog/DialogForm.vue'
import DialogBase from '@/components/dialog/DialogBase.vue'
import campCollaborationDisplayName from '@/common/helpers/campCollaborationDisplayName.js'

export default {
name: 'CollaboratorListItemDeactivate',
Expand All @@ -46,7 +47,10 @@ export default {
if (!(typeof this.entity.user === 'function')) {
return false
}
return this.$auth.user().id === this.entity.user().id
return this.$store.state.auth.user.id === this.entity.user().id
},
displayName() {
return campCollaborationDisplayName(this.entity, this.$tc.bind(this))
},
},
created() {
Expand Down
32 changes: 16 additions & 16 deletions frontend/src/components/navigation/UserMeta.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<template>
<v-menu
v-if="authUser"
v-model="open"
offset-y
dark
Expand All @@ -12,7 +13,7 @@
<template #activator="{ on, value, attrs }">
<v-toolbar-items>
<v-btn right text v-bind="attrs" :class="{ 'v-btn--open': value }" v-on="on">
<user-avatar :user="authUser" :size="40" />
<user-avatar v-if="authUser" :user="authUser" :size="40" />
<span class="sr-only-sm-and-down mx-3">
{{ authUser.displayName }}
</span>
Expand All @@ -31,8 +32,14 @@
}}</span>
</v-list-item>
<v-list-item block tag="li" @click="logout">
<v-icon v-if="logoutIcon" left>{{ logoutIcon }}</v-icon>
<v-progress-circular v-else indeterminate size="18" class="mr-2" />
<v-progress-circular
v-if="logoutInProgress"
indeterminate
size="18"
class="mr-2"
/>
<v-icon v-else left>mdi-logout</v-icon>

<span>{{ $tc('components.navigation.userMeta.logOut') }}</span>
</v-list-item>
</v-list>
Expand All @@ -47,28 +54,21 @@ export default {
components: { UserAvatar },
data() {
return {
logoutIcon: 'mdi-logout',
open: false,
logoutInProgress: false,
}
},
computed: {
authUser() {
return this.$auth.user()
return this.$store.state.auth.user
},
},
methods: {
logout() {
this.logoutIcon = ''
this.$auth.logout()
},
prevent(event) {
event.stopImmediatePropagation()
event.preventDefault()
event.cancelBubble = true
return null
async logout() {
this.logoutInProgress = true
await this.$auth.logout()
this.logoutInProgress = false
},
},
}
</script>

<style scoped></style>
2 changes: 1 addition & 1 deletion frontend/src/components/user/DialogChangeMail.vue
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export default {
showDialog: function (showDialog) {
if (showDialog) {
this.status = 'initial'
this.loadEntityData(this.$auth.user().profile()._meta.self)
this.loadEntityData(this.$store.state.auth.user.profile()._meta.self)
}
},
},
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/user/UserAvatar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default {
},
computed: {
isLoading() {
return (this.user || this.campCollaboration)._meta.loading
return (this.user || this.campCollaboration)?._meta.loading
},
color() {
if (this.isLoading) {
Expand Down
8 changes: 4 additions & 4 deletions frontend/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -163,15 +163,15 @@
},
"invitation": {
"acceptCurrentAuth": "Accept invitation with current account",
"backToHome": "Back to Home",
"backToHome": "Back to home",
"error": "An unexpected error occurred",
"login": "Login",
"notFound": "This invitation is already accepted or was deleted",
"register": "Register",
"reject": "Deny invitation",
"title": "Invitation to Camp",
"useOtherAuth": "Use another account",
"userAlreadyInCamp": "You are already part of this camp",
"title": "Invitation to camp",
"useOtherAuth": "Logout & use another account",
"userAlreadyInCamp": "You are already participating in this camp",
"userWelcome": "Welcome",
"openCamp": "Open camp",
"successfullyRejected": "The invitation was successfully rejected"
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/mixins/campRoleMixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const campRoleMixin = {
return this.role === 'member'
},
role() {
const currentUserLink = this.$auth.user()._meta.self
const currentUserLink = this.$store.state.auth.user._meta.self
const result = this._campCollaborations
.filter((coll) => typeof coll.user === 'function')
.find((coll) => coll.user()._meta.self === currentUserLink)
Expand Down
Loading